建立连接
from exchangelib import DELEGATE, IMPERSONATION, Account, Credentials
#用户名格式为“域名\用户名形式”,有些Exchange服务器需要邮件地址形式`myusername@example.com`,例如Office365。另外,还支持UPN格式。
credentials = Credentials(username='MYWINDOMAIN\\myusername', password='topsecret')
#如果长时间在脚本中运行,可能需要启用容错。容错意味着,如果服务器不可用或响应错误消息,则大幅回退请求并休眠,直到某个阈值后放弃该请求。这样可以防止自动化脚本压垮故障或过载的服务器,并隐藏大型Exchange安装中经常发生的间歇性服务中断情况。
#帐户实例是您要连接到的Exchange服务器上的帐户,这可以是与认证关联的帐户,也可以是授予访问权限的任何其他帐户。例如,如果要访问共享文件夹,需要使用共享文件夹所属帐户的电子邮件地址创建帐户实例,然后通过此帐户访问共享文件夹。
#`primary_smtp_address`为分配给该账户的SMTP地址,如果启用自动发现,也可以使用别名。
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)
# 在Account对象中,将保存所有的自动发现的数据:
my_account.ad_response
# 设置账户信息,然后启用自动发现,就可以查找到EWS的终结点
account = Account(primary_smtp_address='john@example.com', credentials=credentials,
autodiscover=True, access_type=DELEGATE)
# 如果认证拥有目标账户的模拟访问权限,则需要设置`access_type`为IMPERSONATION:
account = Account(primary_smtp_address='john@example.com', credentials=credentials,
autodiscover=True, access_type=IMPERSONATION)
优化连接
from exchangelib import DELEGATE, Account, Configuration, Credentials, NTLM, Build, Version
# 根据MSDN文档, 如果在使用模拟访问时指定帐户的UPN或SID,则可以避免每次请求都进行AD查找。 EWS不能提供这些信息,需要您通过其他方法来获取,例如进行一次AD查找:
account = Account(...)
account.identity.sid = 'S-my-sid'
account.identity.upn = 'john@subdomain.example.com'
# 如果服务器不支持自动发现,或者希望减少自动发现的开销,请使用配置对象来指定服务器位置:
credentials = Credentials(...)
config = Configuration(server='mail.example.com', credentials=credentials)
account = Account(primary_smtp_address='john@example.com', config=config,
autodiscover=False, access_type=DELEGATE)
# `exchangelib`将尝试猜测服务器版本和身份验证方法。如果你希望看到关于验证方法和版本的错误信息,或避免额外的网络流量,可以显式设置身份验证方法和版本:
version = Version(build=Build(15, 0, 12, 34))
config = Configuration(
server='example.com', credentials=credentials, version=version, auth_type=NTLM
)
容错
from exchangelib import Account, FaultTolerance, Configuration, Credentials
from exchangelib.autodiscover import Autodiscovery
# 默认情况下,我们对服务器返回的所有异常都认为操作失败。如果要启用容错,请在配置中添加重试策略。然后我们将针对某些暂时性错误进行重试。默认情况下,我们会大幅后退,然后最多一个小时以后进行重试。
# 配置如下:
credentials = Credentials(...)
config = Configuration(retry_policy=FaultTolerance(max_wait=3600), credentials=credentials)
account = Account(primary_smtp_address='john@example.com', config=config)
# 自动发现功能也将使用此策略,但仅适用于最终的自动发现终结点。以下代码展示如何更改自动发现候选服务器的策略。
Autodiscovery.INITIAL_RETRY_POLICY = FaultTolerance(max_wait=30)
Kerberos和SSPI认证
from exchangelib import Configuration, GSSAPI, SSPI
# Kerberos and SSPI authentication are supported via the GSSAPI and SSPI auth types.
config = Configuration(auth_type=GSSAPI)
config = Configuration(auth_type=SSPI)
基于证书的认证 (CBA)
from exchangelib import Configuration, BaseProtocol, CBA, TLSClientAuth
TLSClientAuth.cert_file = '/path/to/client.pem'
BaseProtocol.HTTP_ADAPTER_CLS = TLSClientAuth
config = Configuration(auth_type=CBA)
OAuth身份认证
# OAuth认证使用`OAUTH2`和`OAuth2Credentials`来实现。对于访问多个帐户的应用程序,使用`OAuth2AuthorizationCodeCredentials`很有用.
from exchangelib import Configuration, OAuth2Credentials, OAuth2AuthorizationCodeCredentials, \
Identity, OAUTH2
from oauthlib.oauth2 import OAuth2Token
credentials = OAuth2Credentials(client_id='MY_ID', client_secret='MY_SECRET', tenant_id='TENANT_ID')
# 使用OAuth2可能需要设置模拟访问标头。如果遇到有关模拟访问错误,请添加OAuth2认证帐户的有关信息:
credentials = OAuth2Credentials(..., identity=Identity(primary_smtp_address='svc_acct@example.com'))
credentials = OAuth2AuthorizationCodeCredentials(..., identity=Identity(upn='svc_acct@subdomain.example.com'))
credentials = OAuth2AuthorizationCodeCredentials(client_id='MY_ID', client_secret='MY_SECRET', authorization_code='AUTH_CODE')
credentials = OAuth2AuthorizationCodeCredentials(
client_id='MY_ID', client_secret='MY_SECRET', access_token=OAuth2Token(access_token='EXISTING_TOKEN')
)
config = Configuration(credentials=credentials, auth_type=OAUTH2)
# 当应用程序使用exchangelib刷新访问令牌时可能希望存储刷新的令牌,这样用户就不必重新授权。 为此,需要继承OAuth2AuthorizationCodeCredentials类,然后重写on_token_auto_refreshed()方法:
class MyCredentials(OAuth2AuthorizationCodeCredentials):
def on_token_auto_refreshed(self, access_token):
store_it_somewhere(access_token)
# Let the object update its internal state!
super().on_token_auto_refreshed(access_token)
# 对于需要外部程序来提供访问令牌的应用, 需要继承OAuth2AuthorizationCodeCredentials重写refresh()方法:
class MyCredentials(OAuth2AuthorizationCodeCredentials):
def refresh(self):
self.access_token = ...
缓存自动发现结果
from exchangelib import Configuration, Credentials, Account, DELEGATE
# 如果您经常连接到同一帐户,则可以缓存自动发现结果以便以后跳过自动发现操作:
account = Account(...)
ews_url = account.protocol.service_endpoint
ews_auth_type = account.protocol.auth_type
primary_smtp_address = account.primary_smtp_address
# 保存版本信息是可选的,可以用来避免一次或多次往返以猜测正确的Exchange服务器版本。
version = account.version
# 现在您就可以创建一个不是用自动发现而使用结果缓存的账户:
credentials = Credentials(...)
config = Configuration(service_endpoint=ews_url, credentials=credentials, auth_type=ews_auth_type, version=version)
account = Account(
primary_smtp_address=primary_smtp_address,
config=config, autodiscover=False,
access_type=DELEGATE,
)
# 自动发现操作需要很多时间,特别是找出特定电子邮件域所关联的自动发现服务器。因此,我们将在磁盘上创建一个可以长期保存的、每个用户的、包含先前成功的域->自动发现服务器查找结果的文件。此文件在进程之间共享,在程序退出时不会删除。
# 如果域中的电子邮件自动发现操作失败,则该域的缓存项将自动删除。如果需要,可以完全清除整个缓存:
from exchangelib.autodiscover import clear_cache
clear_cache()
代理和自定义TLS验证
如果需要代理支持或自定义TLS验证,则可以使用自定义requests.adapters
类,如该内容所述。
以下代码是根据连接的服务器使用不同自定义根证书的示例:
from urllib.parse import urlparse
import requests.adapters
from exchangelib.protocol import BaseProtocol
class RootCAAdapter(requests.adapters.HTTPAdapter):
"""使用硬编码指定根证书路径的一个HTTP"""
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().cert_verify(conn=conn, url=url, verify=cert_file, cert=cert)
# 设置exchangelib的新适配器类:
BaseProtocol.HTTP_ADAPTER_CLS = RootCAAdapter
以下代码是支持代理功能的示例:
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().send(*args, **kwargs)
# 设置exchangelib的新适配器类:
BaseProtocol.HTTP_ADAPTER_CLS = ProxyAdapter
exchangelib提供了一个忽略TLS验证错误的适配器示例:
from exchangelib.protocol import BaseProtocol, NoVerifyHTTPAdapter
# 设置exchangelib的新适配器类:
BaseProtocol.HTTP_ADAPTER_CLS = NoVerifyHTTPAdapter
User-Agent
您可以自定义User-Agent
参数。默认情况下,exchangelib的User-Agent
参数为exchangelib/<version>(python-requests/<version>)
。
from exchangelib.protocol import BaseProtocol
# 设置exchangelib的新user-agent
BaseProtocol.USERAGENT = "Auto-Reply/0.1.0"