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

使用Python MSAL库实现Office 365 IMAP OAuth2认证失败排查

Office 365 IMAP OAuth2(客户端凭证流)认证失败排查

我正尝试将旧版邮件机器人从基础认证(Basic authentication)升级为OAuth2认证,因为基础认证将于两天后废弃。

文档说明应用可保留原有逻辑,仅替换认证部分:

开发人员构建的使用这些协议发送、读取或处理邮件的应用,可保留原有协议,但需为用户实现安全的现代认证体验。该功能基于Microsoft Identity platform v2.0构建,支持访问Microsoft 365邮箱账户。

我明确选择了客户端凭证流(client credentials flow),因为文档指出:

此类授权通常用于无需用户即时交互、需在后台运行的服务器到服务器交互场景。

我编写了Python脚本,使用MSAL库获取Access Token,现在尝试用该Token认证IMAP服务器。脚本如下:

import imaplib
import msal
import logging

app = msal.ConfidentialClientApplication(
    'client-id',
    authority='https://login.microsoftonline.com/tenant-id',
    client_credential='secret-key'
)

result = app.acquire_token_for_client(scopes=['https://graph.microsoft.com/.default'])

def generate_auth_string(user, token):
  return 'user=%s\1auth=Bearer %s\1\1' % (user, token)

# IMAP time!
mailserver = 'outlook.office365.com'
imapport = 993
M = imaplib.IMAP4_SSL(mailserver,imapport)
M.debug = 4
M.authenticate('XOAUTH2', lambda x: generate_auth_string('user@mydomain.com', result['access_token']))

print(result)

IMAP认证失败,即使设置了M.debug = 4,输出信息也无帮助:

22:56.53 > b'DBDH1 AUTHENTICATE XOAUTH2'
  22:56.53 < b'+ '
  22:56.53 write literal size 2048
  22:57.84 < b'DBDH1 NO AUTHENTICATE failed.'
  22:57.84 NO response: b'AUTHENTICATE failed.'
Traceback (most recent call last):
  File "/home/ubuntu/mini-oauth.py", line 21, in <module>
    M.authenticate("XOAUTH2", lambda x: generate_auth_string('user@mydomain.com', result['access_token']))
  File "/usr/lib/python3.10/imaplib.py", line 444, in authenticate
    raise self.error(dat[-1].decode('utf-8', 'replace'))
imaplib.IMAP4.error: AUTHENTICATE failed.

已排查内容

  • 旧方法已失效,其建议的scope无法生成Access Token。
  • 客户端凭证流要求使用https://graph.microsoft.com/.default作为scope,不确定该scope是否包含IMAP资源所需的https://outlook.office.com/IMAP.AccessAsUser.All权限。
  • 验证了生成的SASL XOAUTH2字符串符合微软文档示例:
import base64

user = 'test@contoso.onmicrosoft.com'
token = 'EwBAAl3BAAUFFpUAo7J3Ve0bjLBWZWCclRC3EoAA'

xoauth = "user=%s\1auth=Bearer %s\1\1" % (user, token)

xoauth = xoauth.encode('ascii')
xoauth = base64.b64encode(xoauth)
xoauth = xoauth.decode('ascii')

xsanity = 'dXNlcj10ZXN0QGNvbnRvc28ub25taWNyb3NvZnQuY29tAWF1dGg9QmVhcmVyIEV3QkFBbDNCQUFVRkZwVUFvN0ozVmUwYmpMQldaV0NjbFJDM0VvQUEBAQ=='

print(xoauth == xsanity) # prints True
  • 有资料提到可能需要获取多个Token,一个用于Graph,一个用于IMAP连接,这是否是我缺失的步骤?

疑问

请问我哪里出错了?或者如何从IMAP服务器获取更详细的认证失败原因?


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 18:50:25