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

使用Python exchangelib读取Exchange共享邮箱遇invalid_token错误

问题:使用exchangelib读取Exchange共享邮箱时遇到invalid_token错误

我尝试用Python的exchangelib库读取Exchange共享邮箱,代码如下:

def getExchangeMailBox():

    username = 'user@domain.com' ## make sure to give valid address
    tenant_id = '<mytenantid>'
    client_id = '<myclientid>'
    secret_value = '<mysecret>'
    version = Version(build=Build(15, 0, 12, 34))
    credentials = OAuth2Credentials(client_id=client_id, client_secret=secret_value, tenant_id=tenant_id,identity=username)

    config = Configuration(service_endpoint = 'https://outlook.office365.com/EWS/Exchange.asmx',
                            credentials=credentials,
                            auth_type=OAUTH2 , 
                            version=version)
    account = Account(primary_smtp_address=username, credentials=credentials, autodiscover=False, config=config, access_type=IMPERSONATION)
    for item in account.inbox.all().order_by("-datetime_received")[:100]:
            logger.info(item.subject, item.sender, item.datetime_received)

已在Entra门户注册应用,并配置了以下Microsoft Graph权限:

  • EWS.AccessAsUser.All
  • Mail.Read
  • User.Read

但运行时出现如下错误:

WARNING:tzlocal:/etc/timezone is deprecated on Debian, and no longer reliable. Ignoring.
ERROR:visualizer:Exception on / [GET]
Traceback (most recent call last):
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/cached_property.py", line 63, in __get__
return obj_dict[name]
KeyError: 'inbox'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/cached_property.py", line 63, in __get__
return obj_dict[name]
KeyError: 'root'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/flask/app.py", line 1511, in wsgi_app
response = self.full_dispatch_request()
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/flask/app.py", line 919, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/flask/app.py", line 917, in full_dispatch_request
rv = self.dispatch_request()
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/flask/app.py", line 902, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
File "/home/adm-mfrau/visualizer/visualizer.py", line 69, in returnExcelDF
getExchangeMailBox()
File "/home/adm-mfrau/visualizer/visualizer.py", line 55, in getExchangeMailBox
for item in account.inbox.all().order_by("-datetime_received")[:100]:
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/cached_property.py", line 67, in __get__
return obj_dict.setdefault(name, self.func(obj))
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/exchangelib/account.py", line 286, in inbox
return self.root.get_default_folder(Inbox)
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/cached_property.py", line 67, in __get__
return obj_dict.setdefault(name, self.func(obj))
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/exchangelib/account.py", line 350, in root
return Root.get_distinguished(account=self)
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/exchangelib/folders/roots.py", line 145, in get_distinguished
return cls._get_distinguished(
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/exchangelib/folders/base.py", line 226, in _get_distinguished
return cls.resolve(account=folder.account, folder=folder)
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/exchangelib/folders/base.py", line 530, in resolve
folders = list(FolderCollection(account=account, folders=[folder]).resolve())
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/exchangelib/folders/collections.py", line 335, in resolve
yield from self.__class__(account=self.account, folders=resolveable_folders).get_folders(
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/exchangelib/folders/collections.py", line 403, in get_folders
yield from GetFolder(account=self.account).call(
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/exchangelib/services/get_folder.py", line 51, in _elems_to_objs
for folder, elem in zip(self.folders, elems):
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/exchangelib/services/common.py", line 279, in _chunked_get_elements
yield from self._get_elements(payload=payload_func(chunk, **kwargs))
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/exchangelib/services/common.py", line 300, in _get_elements
yield from self._response_generator(payload=payload)
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/exchangelib/services/common.py", line 263, in _response_generator
response = self._get_response_xml(payload=payload)
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/exchangelib/services/common.py", line 396, in _get_response_xml
r = self._get_response(payload=payload, api_version=api_version)
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/exchangelib/services/common.py", line 347, in _get_response
r, session = post_ratelimited(
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/exchangelib/util.py", line 866, in post_ratelimited
protocol.retry_policy.raise_response_errors(r)
File "/home/adm-mfrau/visualizer/.venv/lib/python3.10/site-packages/exchangelib/protocol.py", line 738, in raise_response_errors
raise MalformedResponseError(
exchangelib.errors.MalformedResponseError: Unknown failure in response. Code: 403 headers: {'Cache-Control': 'private', 'Content-Length': '0', 'Content-Type': 'text/xml; charset=utf-8', 'Server': 'Microsoft-HTTPAPI/2.0', 'X-BEServer': 'MI2P293MB0038', 'X-NanoProxy': '1', 'X-AspNet-Version': '4.0.30319', 'Request-Id': '91119436-71b9-dd61-0833-cb1ba8e3e1be', 'X-CalculatedBETarget': 'MI2P293MB0038.ITAP293.PROD.OUTLOOK.COM', 'Restrict-Access-Confirm': '1', 'X-BeSku': 'WCS7', 'X-BackEndHttpStatus': '403', 'X-DiagInfo': 'MI2P293MB0038', 'x-ms-appId': '79909861-20d8-4e21-8d3a-8e79e9baee06', 'X-Proxy-BackendServerStatus': '403', 'X-Proxy-RoutingCorrectness': '1', 'X-RUM-NotUpdateQueriedPath': '1', 'X-RUM-NotUpdateQueriedDbCopy': '1', 'X-RUM-Validated': '1', 'X-UserType': 'Business', 'X-FEServer': 'ZR2P278CA0072', 'X-FirstHopCafeEFZ': 'ZRH', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains', 'MS-CV': 'NpQRkblxYd0IM8sbqOPhvg.1', 'Set-Cookie': 'exchangecookie=afb09f614196456b8d7b6fa8c4862b87; expires=Thu, 05-Mar-2026 17:15:57 GMT; path=/; secure; HttpOnly', 'WWW-Authenticate': 'Bearer client_id="00000002-0000-0ff1-ce00-000000000000", trusted_issuers="00000001-0000-0000-c000-000000000000@*", token_types="app_asserted_user_v1 service_asserted_app_v1", error="invalid_token"', 'Date': 'Wed, 05 Mar 2025 17:15:57 GMT'} content:
INFO:__main__:Finished

无法定位token_types="app_asserted_user_v1 service_asserted_app_v1", error="invalid_token"的问题原因,已在Entra ID应用中完成配置。


问题排查与解决方法

1. 权限类型不匹配

你配置的EWS.AccessAsUser.All是委托权限,但当前用的是客户端凭证(client secret)的应用权限模式,需要配置应用权限的EWS.AccessAsApp:

  • 登录Entra门户,找到目标应用,进入「API权限」
  • 添加Exchange Web Services的应用权限EWS.AccessAsApp,并完成管理员同意

2. 身份认证参数错误

客户端凭证流不需要identity参数,且access_type设置有误:

  • 移除OAuth2Credentials中的identity=username参数
  • 将Account初始化的access_type改为DELEGATE(应用权限模式下无需模拟用户)

3. Exchange版本适配问题

指定的Build(15, 0, 12, 34)版本过旧,不适用于Office365:

  • 改用Version.latest()自动适配最新版本,或明确指定兼容Office365的版本(如Version(build=Build(15, 20, 5447, 10)))

4. 修改后的示例代码

def getExchangeMailBox():
    tenant_id = '<mytenantid>'
    client_id = '<myclientid>'
    secret_value = '<mysecret>'
    # 使用Office365兼容的最新版本
    version = Version.latest()
    # 客户端凭证流无需identity参数
    credentials = OAuth2Credentials(
        client_id=client_id, 
        client_secret=secret_value, 
        tenant_id=tenant_id
    )

    config = Configuration(
        service_endpoint='https://outlook.office365.com/EWS/Exchange.asmx',
        credentials=credentials,
        auth_type=OAUTH2, 
        version=version
    )
    # 替换为共享邮箱的SMTP地址
    account = Account(
        primary_smtp_address='shared_mailbox@domain.com',
        credentials=credentials,
        autodiscover=False,
        config=config,
        access_type=DELEGATE
    )
    for item in account.inbox.all().order_by("-datetime_received")[:100]:
        logger.info(f"主题: {item.subject}, 发件人: {item.sender}, 接收时间: {item.datetime_received}")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 23:18:10