Linux虚拟机下无应用密码时,如何通过Python exchangelib模块结合EWS访问Outlook收件箱?
无需应用密码访问Outlook邮箱(EWS + exchangelib)的OAuth2认证方案
没问题,既然平台禁用了应用密码,OAuth2认证是微软官方推荐的安全替代方案,而且能和exchangelib在Linux虚拟机上完美配合。下面是一步步的实现指南:
1. 在Azure AD中注册应用
首先需要在Azure Active Directory里注册一个应用,用来获取OAuth2的认证凭据:
- 登录Azure门户,进入「Azure Active Directory」→「应用注册」,点击「新注册」
- 选择「单租户」(如果你的邮箱属于企业租户),重定向URI选「公共客户端/本机」,填入
http://localhost即可(Linux环境下调试或使用设备码流时足够) - 注册完成后,记下客户端ID(Application ID)和租户ID(Directory ID),后面会用到
2. 配置应用权限
给注册的应用添加访问Exchange Online的权限:
- 进入应用的「API权限」页面,点击「添加权限」→选择「Exchange」→「应用权限」
- 添加
EWS.AccessAsApp权限,然后点击「授予管理员同意」(需要租户管理员权限操作)
3. 选择适合Linux环境的OAuth2认证流
根据你的脚本场景,选下面两种认证流之一:
设备码流(交互式,适合调试/个人脚本)
这种方式不需要客户端密钥,适合无GUI的Linux服务器,需要用户通过浏览器完成一次授权:
- 只需要前面记下的客户端ID和租户ID
- 运行脚本时会输出一个链接和验证码,用户在任意设备的浏览器打开链接,输入验证码并登录自己的Outlook账号即可完成授权
客户端凭据流(非交互式,适合后台服务脚本)
这种方式完全不需要用户交互,适合长期运行的后台脚本:
- 在应用的「证书和密码」页面,点击「新建客户端密码」,生成后记下密码值(生成后就无法再次查看,一定要保存好)
- 依赖之前配置的
EWS.AccessAsApp权限,且必须已经获得管理员同意
4. 修改exchangelib代码适配OAuth2
先确保你的exchangelib是最新版本:
pip install --upgrade exchangelib
设备码流代码示例
from exchangelib import Account, OAuth2DeviceCodeCredentials # 替换成你的实际信息 TENANT_ID = "你的租户ID" CLIENT_ID = "你的客户端ID" EMAIL_ADDRESS = "你的Outlook邮箱地址" # 初始化设备码认证 credentials = OAuth2DeviceCodeCredentials( client_id=CLIENT_ID, tenant_id=TENANT_ID, scopes=["https://outlook.office365.com/EWS.AccessAsUser.All"] ) # 连接邮箱 account = Account( primary_smtp_address=EMAIL_ADDRESS, credentials=credentials, autodiscover=True, access_type="delegate" ) # 测试访问收件箱 print(f"收件箱最新10封邮件数: {len(account.inbox.all().order_by('-datetime_received')[:10])}")
客户端凭据流代码示例
from exchangelib import Account, OAuth2ClientCredentials # 替换成你的实际信息 TENANT_ID = "你的租户ID" CLIENT_ID = "你的客户端ID" CLIENT_SECRET = "你的客户端密码" EMAIL_ADDRESS = "你的Outlook邮箱地址" # 初始化客户端凭据认证 credentials = OAuth2ClientCredentials( client_id=CLIENT_ID, client_secret=CLIENT_SECRET, tenant_id=TENANT_ID, scopes=["https://outlook.office365.com/.default"] ) # 连接邮箱(应用级权限需设置access_type为impersonation) account = Account( primary_smtp_address=EMAIL_ADDRESS, credentials=credentials, autodiscover=True, access_type="impersonation" ) # 测试访问收件箱 print(f"收件箱最新10封邮件数: {len(account.inbox.all().order_by('-datetime_received')[:10])}")
注意事项
- 如果使用设备码流,第一次授权后,exchangelib会自动缓存令牌,后续运行脚本无需再次授权
- 客户端凭据流的客户端密码有效期可以自定义,到期前记得重新生成并更新脚本
- 确保你的Linux虚拟机可以访问Azure AD和Exchange Online的相关域名(比如
login.microsoftonline.com、outlook.office365.com)
内容的提问来源于stack exchange,提问作者Seshu




