I have been trying to access a mailbox within my Organisation's exchange server with the following code :
from exchangelib import Credentials, Account, DELEGATE, Configuration,NTLM, IMPERSONATION, FaultTolerance,EWSDateTime,EWSTimeZone,Message,Q
import datetime
import getpass
import logging
logging.basicConfig(level=logging.DEBUG)
user_name = 'Test.Helpdesk'
new_password = getpass.getpass(prompt='Password: ', stream=None)
try:
credentials = Credentials(username = user_name, password = new_password)
config = Configuration(server ='example.com', credentials = credentials)
account = Account(primary_smtp_address = "Test.Helpdesk@example.com", credentials = credentials, config = config, autodiscover = False)
print("Success")
except Exception as e:
print(e)
I keep getting the same error every-time :
HTTPSConnectionPool(host='example.com', port=443): Max retries exceeded with url: /EWS/Exchange.asmx (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x00000178A6AD8608>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed'))
I tried to follow the following SO post:
SSL: CERTIFICATE_VERIFY_FAILED when connecting to a company Exchange Server
This :
import requests
print (requests.certs.where())
Gave me the directory path where I found a .pem file.
Then this :
import ssl
context = ssl.create_default_context()
der_certs = context.get_ca_certs(binary_form=True)
pem_certs = [ssl.DER_cert_to_PEM_cert(der) for der in der_certs]
with open('wincacerts.pem', 'w') as outfile:
for pem in pem_certs:
outfile.write(pem + '\n')
I replaced the name "wincacerts" to "cacerts", since that is the name of the file I found in the directory that the previous code pointed me to.
Then this :
import os
import requests
root_path = os.getcwd()
path_pem=os.path.join(".....\\cacerts.pem")
requests.get('https://example.com', verify=path_pem
Gave me : <Response [401]>
I'm not sure what this means.
Now finally, according to the solution from the SO post (link given above), I am supposed to use the following code and make changes according to my needs :
#EXAMPLE FROM ANOTHER SO. POST
root_path = os.getcwd()
path_pem=os.path.join(root_path, 'files', 'wincacerts.crt')
class RootCAAdapter(requests.adapters.HTTPAdapter):
# An HTTP adapter that uses a custom root CA certificate at a hard coded location
def cert_verify(self, conn, url, verify, cert):
cert_file = {
'mail.ourserver.loc': path_pem,
'mail.internal': '/path/to/mail.internal.crt'
}[urlparse(url).hostname]
super(RootCAAdapter, self).cert_verify(conn=conn, url=url, verify=cert_file, cert=cert)
# Tell exchangelib to use this adapter class instead of the default
BaseProtocol.HTTP_ADAPTER_CLS = RootCAAdapter
The problem is that I do not have knowledge about SSL and Certificates and how they work, so I don't know what changes to do in the above code that would work for me. Also, I have been informed that the servers at my organisation work only on TLS 1.2.
These are the exact lines from my Network Dept. :
Make sure your application configure TLS1.2. Server supports only TLS 1.2.
Is there an way to configure TLS to 1.2 in the exchangelib code ?
Update
I came across this link https://github.com/ecederstrand/exchangelib/issues/155
and it mentions that the issue can be solved using the HTTPAdapter class
.
It would be of great help if someone could shed some light of how the class works and the variables that need to be changed according to personal requirements.
Not much is discussed in the documentation, https://ecederstrand.github.io/exchangelib/