You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

exchangelib 4.7.3连接Office 365共享邮箱报未授权错误排查

问题背景

需要编写Python脚本检测托管在Office 365上的共享邮箱入站邮件,开发使用exchangelib 4.7.3版本,初始测试代码如下:

#!/usr/bin/env python3

import logging
from exchangelib import Credentials, Account, Configuration, DELEGATE


def list_mails():
    credentials = Credentials('user@company.com', 'SecretPassword')
    config = Configuration(server='outlook.office365.com', credentials=credentials)
    account = Account(primary_smtp_address='sharedmailbox@company.com', config=config, autodiscover=False, access_type=DELEGATE)

    for item in account.inbox.all().order_by('-datetime_received')[:100]:
        print(item.subject, item.sender, item.datetime_received)


def main():
   list_mails()

if __name__ == "__main__":
    logging.basicConfig(level=logging.DEBUG)
    main()

故障现象

多次调整配置后运行代码始终抛出权限错误,核心报错信息如下:

DEBUG:exchangelib.protocol:No retry: no fail-fast policy
DEBUG:exchangelib.protocol:Server outlook.office365.com: Retiring session 87355
DEBUG:exchangelib.protocol:Server outlook.office365.com: Created session 82489
DEBUG:exchangelib.protocol:Server outlook.office365.com: Releasing session 82489
Traceback (most recent call last):
  File "/Users/test/Code/./orderalert.py", line 24, in <module>
    main()
  File "/Users/test/Code/./orderalert.py", line 20, in main
    list_mails()
  File "/Userstest/Code/./orderalert.py", line 11, in list_mails
    account = Account(primary_smtp_address='sharedmailbox@company.com', config=config, autodiscover=False, access_type=DELEGATE)
  File "/opt/homebrew/lib/python3.9/site-packages/exchangelib/account.py", line 204, in __init__
    self.version = self.protocol.version.copy()
  File "/opt/homebrew/lib/python3.9/site-packages/exchangelib/protocol.py", line 483, in version
    self.config.version = Version.guess(self, api_version_hint=self._api_version_hint)
  File "/opt/homebrew/lib/python3.9/site-packages/exchangelib/version.py", line 233, in guess
    list(ResolveNames(protocol=protocol).call(unresolved_entries=[name]))
  File "/opt/homebrew/lib/python3.9/site-packages/exchangelib/services/common.py", line 187, in _elems_to_objs
    for elem in elems:
  File "/opt/homebrew/lib/python3.9/site-packages/exchangelib/services/common.py", line 245, in _chunked_get_elements
    yield from self._get_elements(payload=payload_func(chunk, **kwargs))
  File "/opt/homebrew/lib/python3.9/site-packages/exchangelib/services/common.py", line 265, in _get_elements
    yield from self._response_generator(payload=payload)
  File "/opt/homebrew/lib/python3.9/site-packages/exchangelib/services/common.py", line 227, in _response_generator
    response = self._get_response_xml(payload=payload)
  File "/opt/homebrew/lib/python3.9/site-packages/exchangelib/services/common.py", line 343, in _get_response_xml
    r = self._get_response(payload=payload, api_version=api_version)
  File "/opt/homebrew/lib/python3.9/site-packages/exchangelib/services/common.py", line 297, in _get_response
    r, session = post_ratelimited(
  File "/opt/homebrew/lib/python3.9/site-packages/exchangelib/util.py", line 917, in post_ratelimited
    protocol.retry_policy.raise_response_errors(r)
  File "/opt/homebrew/lib/python3.9/site-packages/exchangelib/protocol.py", line 688, in raise_response_errors
    raise UnauthorizedError(f"Invalid credentials for {response.url}")
exchangelib.errors.UnauthorizedError: Invalid credentials for https://outlook.office365.com/EWS/Exchange.asmx
DEBUG:exchangelib.protocol:Server outlook.office365.com: Closing sessions

已尝试的无效排查方案

  • 确认user@company.com凭据有效,可正常登录网页端,账号未强制启用MFA等验证策略
  • 尝试开启autodiscover自动发现模式创建Account实例,代码为account = Account('sharedmailbox@company.com', credentials=credentials, autodiscover=True, access_type=DELEGATE)
  • 连接时禁用TLS验证
  • 按建议为邮箱地址配置on.company.com的on子域名
  • 在微软官方连接测试站点验证自动发现整体配置正常
  • Office 365 Azure AD管理后台可看到脚本发起的登录记录为成功状态
故障根因

该问题和代码逻辑、本地网络配置无关,由三点共同导致:

  1. 微软自2022年10月起对所有Exchange Online租户默认禁用EWS协议的基础身份验证(Basic Auth),原代码中用明文账号密码初始化Credentials的方式走的就是已被禁用的Basic Auth流程。Azure AD后台显示登录成功仅代表账号密码合法性校验通过,到EWS协议鉴权环节会被微软直接拦截返回401,触发凭据无效报错。
  2. 使用的exchangelib 4.7.3版本未适配Office 365的OAuth2现代认证默认配置,无论怎么调整Basic Auth相关参数都无法绕过微软的安全限制。
  3. 即使认证方式配置正确,如果委托账号未被显式授予目标共享邮箱的「完全访问(Full Access)」权限,或是Exchange管理中心禁用了该委托账号的EWS协议访问权限,也会触发完全相同的401错误。
修复方案

按以下步骤操作即可解决:

  1. 先升级exchangelib到最新稳定版,旧版本对Office 365的OAuth2支持存在已知bug:
    pip install --upgrade exchangelib
    
  2. 到Exchange Online管理中心确认两项权限配置:
    • 找到登录用的委托账号user@company.com,在邮箱功能设置中确认EWS协议为允许状态
    • 找到目标共享邮箱sharedmailbox@company.com,在委派权限设置中给user@company.com添加「完全访问」权限,添加后等待15分钟等待权限跨节点同步生效
  3. 替换原有认证逻辑,使用OAuth2交互式认证适配Office 365,可直接运行的参考代码如下:
    #!/usr/bin/env python3
    import logging
    from exchangelib import Account, Configuration, DELEGATE, O365InteractiveCredentials
    
    def list_mails():
        # 首次运行会弹出浏览器完成账号登录,后续会本地缓存token无需重复认证
        # 客户端ID使用微软官方公开的Office桌面端EWS应用ID,无需自行注册Azure应用
        credentials = O365InteractiveCredentials(
            client_id='d3590ed6-52b3-4102-aeff-aad2292ab01c',
            username='user@company.com'
        )
        config = Configuration(server='outlook.office365.com', credentials=credentials)
        account = Account(
            primary_smtp_address='sharedmailbox@company.com',
            config=config,
            autodiscover=False,
            access_type=DELEGATE
        )
    
        for item in account.inbox.all().order_by('-datetime_received')[:100]:
            print(item.subject, item.sender, item.datetime_received)
    
    def main():
        list_mails()
    
    if __name__ == "__main__":
        logging.basicConfig(level=logging.WARNING)
        main()
    

    提示:如果需要完全无人值守运行,可在Azure AD注册公共客户端应用,授予应用EWS.AccessAsUser.All委托权限,开启公共客户端流后替换为OAuth2Credentials传入凭证即可。


内容的提问来源于stack exchange,提问作者Kami

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 07:21:27