Python通过代理服务器连接O365时出现HTTPS连接失败问题
问题现象
本地运行正常的O365邮件读写代码,部署到需代理访问外网的服务器时,出现连接超时错误:
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='login.microsoftonline.com', port=443): Max retries exceeded with url: /2d11ad74-bbf6-403f-32c7-6ff0e039a923/oauth2/v2.0/token (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x000002507067C348>: Failed to establish a new connection: [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond'))
原代码如下:
import settings from exchangelib import Credentials, Account, DELEGATE, BASIC, \ Configuration, NTLM, Message, Mailbox, FileAttachment, HTMLBody, FaultTolerance, IMPERSONATION from exchangelib.protocol import BaseProtocol, NoVerifyHTTPAdapter from exchangelib import OAuth2LegacyCredentials credentials = OAuth2LegacyCredentials( client_id= settings.clientId, client_secret= settings.clientSecret, tenant_id=settings.tenentId, username=settings.eUserName, password=settings.ePassword ) config = Configuration(server = 'smtp.office365.com', credentials=credentials) account = Account(settings.eUserName, config=config, access_type=DELEGATE) m = Message( account=account, subject='Any Subject OAth2 Authentication', body=HTMLBody('OAth2 Authentication'), to_recipients=map(lambda x: Mailbox(email_address=x), ['myEmail@gmail.com']) ) for item in account.inbox.all()[:10]: print (item.sender.email_address) m.send() print('Email is being sent...')
问题原因
代码未配置代理服务器信息,导致无法通过代理连接微软OAuth2认证服务器(login.microsoftonline.com),进而无法获取访问令牌,最终触发连接超时。
解决方案
exchangelib基于requests库实现网络请求,只需为其协议层配置代理即可。具体步骤如下:
- 配置代理地址、端口(若需认证需额外添加用户名和密码)
- 为BaseProtocol挂载带代理的HTTP适配器
修改后的完整代码:
import settings from exchangelib import Credentials, Account, DELEGATE, \ Configuration, Message, Mailbox, HTMLBody from exchangelib.protocol import BaseProtocol, NoVerifyHTTPAdapter from exchangelib import OAuth2LegacyCredentials import requests # 配置代理信息,替换为实际代理地址和端口 PROXY_URL = "http://your-proxy-server:port" # 若代理需认证,使用格式:"http://username:password@your-proxy-server:port" # 创建带代理的会话 session = requests.Session() session.proxies = { "http": PROXY_URL, "https": PROXY_URL, } # 挂载适配器到exchangelib协议层 BaseProtocol.HTTP_ADAPTER_CLS = NoVerifyHTTPAdapter BaseProtocol.session = session credentials = OAuth2LegacyCredentials( client_id=settings.clientId, client_secret=settings.clientSecret, tenant_id=settings.tenentId, username=settings.eUserName, password=settings.ePassword ) # 修正服务器地址:exchangelib使用EWS协议,需指向outlook.office365.com config = Configuration(server='outlook.office365.com', credentials=credentials) account = Account(settings.eUserName, config=config, access_type=DELEGATE) m = Message( account=account, subject='OAuth2 Authentication 测试邮件', body=HTMLBody('这是OAuth2认证的测试邮件'), to_recipients=[Mailbox(email_address='myEmail@gmail.com')] ) # 读取收件箱前10封邮件 for item in account.inbox.all()[:10]: print(item.sender.email_address) m.send() print('邮件已发送...')
额外注意事项
- 确保代理服务器支持HTTPS请求,地址、端口配置准确
- 若代理需要身份认证,在PROXY_URL中按格式加入用户名和密码
- 原代码中
server配置为smtp.office365.com错误,exchangelib依赖EWS协议,必须使用outlook.office365.com
内容的提问来源于stack exchange,提问作者M. Antoney

