搬自:https://pypi.org/project/exchangelib/
Teaser
Here's a short example of how exchangelib
works. Let's print the first 100 inbox messages in reverse order:
from exchangelib import Credentials, Account credentials = Credentials('john@example.com', 'topsecret') account = Account('john@example.com', credentials=credentials, autodiscover=True) for item in account.inbox.all().order_by('-datetime_received')[:100]: print(item.subject, item.sender, item.datetime_received)
Installation
You can install this package from PyPI:
pip install exchangelib
The default installation does not support Kerberos. For additional Kerberos support, install with the extra kerberos
dependencies:
pip install exchangelib[kerberos]
To install the very latest code, install directly from GitHub instead:
pip install git+https://github.com/ecederstrand/exchangelib.git
exchangelib
uses the lxml
package, and pykerberos
to support Kerberos authentication. To be able to install these, you may need to install some additional operating system packages.
On Ubuntu:
apt-get install libxml2-dev libxslt1-dev # For Kerberos support, also install these: apt-get install libkrb5-dev build-essential libssl-dev libffi-dev python-dev
On CentOS:
# For Kerberos support, install these: yum install gcc python-devel krb5-devel krb5-workstation python-devel
On FreeBSD, pip
needs a little help:
pkg install libxml2 libxslt CFLAGS=-I/usr/local/include pip install lxml # For Kerberos support, also install these: pkg install krb5 CFLAGS=-I/usr/local/include pip install kerberos pykerberos
For other operating systems, please consult the documentation for the Python package that fails to install.
Setup and connecting
from exchangelib import DELEGATE, IMPERSONATION, Account, Credentials, ServiceAccount, \ Configuration, NTLM, GSSAPI, Build, Version # Specify your credentials. Username is usually in WINDOMAIN\username format, where WINDOMAIN is # the name of the Windows Domain your username is connected to, but some servers also # accept usernames in PrimarySMTPAddress ('myusername@example.com') format (Office365 requires it). # UPN format is also supported, if your server expects that. credentials = Credentials(username='MYWINDOMAIN\\myusername', password='topsecret') # If you're running long-running jobs, you may want to enable fault-tolerance. Fault-tolerance # means that requests to the server do an exponential backoff and sleep for up to a certain # threshold before giving up, if the server is unavailable or responding with error messages. # This prevents automated scripts from overwhelming a failing or overloaded server, and hides # intermittent service outages that often happen in large Exchange installations. # If you want to enable the fault tolerance, create credentials as a service account instead: credentials = ServiceAccount(username='FOO\\bar', password='topsecret') # An Account is the account on the Exchange server that you want to connect to. This can be # the account associated with the credentials you connect with, or any other account on the # server that you have been granted access to. If, for example, you want to access a shared # folder, create an Account instance using the email address of the account that the shared # folder belongs to, and access the shared folder through this account. # 'primary_smtp_address' is the primary SMTP address assigned the account. If you enable # autodiscover, an alias address will work, too. In this case, 'Account.primary_smtp_address' # will be set to the primary SMTP address. my_account = Account(primary_smtp_address='myusername@example.com', credentials=credentials, autodiscover=True, access_type=DELEGATE) johns_account = Account(primary_smtp_address='john@example.com', credentials=credentials, autodiscover=True, access_type=DELEGATE) marys_account = Account(primary_smtp_address='mary@example.com', credentials=credentials, autodiscover=True, access_type=DELEGATE) still_marys_account = Account(primary_smtp_address='alias_for_mary@example.com', credentials=credentials, autodiscover=True, access_type=DELEGATE) # Set up a target account and do an autodiscover lookup to find the target EWS endpoint. account = Account(primary_smtp_address='john@example.com', credentials=credentials, autodiscover=True, access_type=DELEGATE) # If your credentials have been given impersonation access to the target account, set a # different 'access_type': account = Account(primary_smtp_address='john@example.com', credentials=credentials, autodiscover=True, access_type=IMPERSONATION) # If the server doesn't support autodiscover, or you want to avoid the overhead of autodiscover, # use a Configuration object to set the server location instead: config = Configuration(server='mail.example.com', credentials=credentials) account = Account(primary_smtp_address='john@example.com', config=config, autodiscover=False, access_type=DELEGATE) # 'exchangelib' will attempt to guess the server version and authentication method. If you # have a really bizarre or locked-down installation and the guessing fails, or you want to avoid # the extra network traffic, you can set the auth method and version explicitly instead: version = Version(build=Build(15, 0, 12, 34)) config = Configuration( server='example.com', credentials=credentials, version=version, auth_type=NTLM ) # Kerberos authentication is supported via the 'gssapi' auth type. Enabling it is slightly awkward, # does not work with autodiscover (yet) and is likely to change in future versions. credentials = Credentials('', '') config = Configuration(server='example.com', credentials=credentials, auth_type=GSSAPI) # If you're connecting to the same account very often, you can cache the autodiscover result for # later so you can skip the autodiscover lookup: ews_url = account.protocol.service_endpoint ews_auth_type = account.protocol.auth_type primary_smtp_address = account.primary_smtp_address # You can now create the Account without autodiscovering, using the cached values: config = Configuration(service_endpoint=ews_url, credentials=credentials, auth_type=ews_auth_type) account = Account( primary_smtp_address=primary_smtp_address, config=config, autodiscover=False, access_type=DELEGATE, ) # Autodiscover can take a lot of time, specially the part that figures out the autodiscover # server to contact for a specific email domain. For this reason, we will create a persistent, # per-user, on-disk cache containing a map of previous, successful domain -> autodiscover server # lookups. This cache is shared between processes and is not deleted when your program exits. # A cache entry for a domain is removed automatically if autodiscovery fails for an email in that # domain. It's possible to clear the entire cache completely if you want: from exchangelib.autodiscover import _autodiscover_cache _autodiscover_cache.clear()
Proxies and custom TLS validation
If you need proxy support or custom TLS validation, you can supply a custom 'requests' transport adapter class, as described in http://docs.python-requests.org/en/master/user/advanced/#transport-adapters.
Here's an example using different custom root certificates depending on the server to connect to:
from urllib.parse import urlparse import requests.adapters from exchangelib.protocol import BaseProtocol 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 = { 'example.com': '/path/to/example.com.crt', '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
Here's an example of adding proxy support:
import requests.adapters from exchangelib.protocol import BaseProtocol class ProxyAdapter(requests.adapters.HTTPAdapter): def send(self, *args, **kwargs): kwargs['proxies'] = { 'http': 'http://10.0.0.1:1243', 'https': 'http://10.0.0.1:4321', } return super(ProxyAdapter, self).send(*args, **kwargs) # Tell exchangelib to use this adapter class instead of the default BaseProtocol.HTTP_ADAPTER_CLS = ProxyAdapter
exchangelib
provides a sample adapter which ignores TLS validation errors. Use at own risk.
from exchangelib.protocol import BaseProtocol, NoVerifyHTTPAdapter # Tell exchangelib to use this adapter class instead of the default BasePro