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

非交互式获取Outlook访问令牌及imaplib XOAUTH2适配问题咨询

非交互式获取XOAUTH2令牌及imaplib集成方案

核心问题解答

  • 获取到有效XOAUTH2令牌后,完全可以直接在imaplib中指定XOAUTH2作为认证机制,只需按照IMAP XOAUTH2的格式构造认证字符串即可。

错误原因分析

  • AADSTS65001:acquire_token_by_username_password失败,大概率是因为账号启用了MFA(多因素认证),或者微软租户禁用了旧版身份验证。该模式仅支持无MFA的账号且租户未禁用旧版认证,目前微软已逐步淘汰该方式。
  • AADSTS7000218:acquire_token_interactive失败,通常是因为应用注册时未正确配置重定向URI,或者端口设置无效。交互式模式需要在应用注册中添加对应的公共客户端重定向URI(比如http://localhost)。

非交互式令牌获取示例代码

方案1:设备码流(适合无UI的服务器场景,首次手动授权后自动刷新)

该模式无需在服务器端操作浏览器,只需在任意设备上输入验证码完成一次授权,后续程序可自动缓存并刷新令牌。

import msal
import imaplib
import base64

# 配置信息
CLIENT_ID = "你的应用客户端ID"
TENANT_ID = "你的租户ID(或填common)"
SCOPES = ["https://outlook.office.com/IMAP.AccessAsUser.All"]  # 注意IMAP权限用outlook端点,不是graph
USER_EMAIL = "你的邮箱地址"

# 初始化MSAL应用
app = msal.PublicClientApplication(CLIENT_ID, authority=f"https://login.microsoftonline.com/{TENANT_ID}")

# 检查缓存中是否有有效令牌
accounts = app.get_accounts(username=USER_EMAIL)
result = None
if accounts:
    result = app.acquire_token_silent(SCOPES, account=accounts[0])

if not result:
    # 发起设备码流
    flow = app.initiate_device_flow(scopes=SCOPES)
    if "user_code" not in flow:
        raise Exception(f"设备码流初始化失败:{flow.get('error_description', '未知错误')}")
    print(f"请访问 {flow['verification_uri']} 并输入代码:{flow['user_code']}")
    result = app.acquire_token_by_device_flow(flow)

if "access_token" in result:
    # 构造XOAUTH2认证字符串
    auth_string = f"user={USER_EMAIL}\x01auth=Bearer {result['access_token']}\x01\x01"
    auth_bytes = base64.b64encode(auth_string.encode("utf-8"))
    auth_base64 = auth_bytes.decode("utf-8")

    # 连接Outlook IMAP服务器
    imap = imaplib.IMAP4_SSL("outlook.office365.com", 993)
    imap.authenticate("XOAUTH2", lambda x: auth_base64)

    # 后续操作示例:列出收件箱邮件
    imap.select("INBOX")
    status, messages = imap.search(None, "ALL")
    print(f"收件箱邮件数量:{len(messages[0].split())}")

    # 关闭连接
    imap.close()
    imap.logout()
else:
    raise Exception(f"获取令牌失败:{result.get('error_description', result.get('error'))}")

方案2:客户端凭据流(适合完全无人工干预的后台服务,需管理员授权)

如果是纯后台服务,可使用应用权限(而非委派权限),需要Azure AD管理员在应用注册中添加IMAP.AccessAsApp权限并授予管理员同意。

import msal
import imaplib
import base64

# 配置信息
CLIENT_ID = "你的应用客户端ID"
CLIENT_SECRET = "你的应用客户端密钥"
TENANT_ID = "你的租户ID"
USER_EMAIL = "要访问的用户邮箱地址"
SCOPES = ["https://outlook.office365.com/.default"]  # 应用权限需用.default范围

# 初始化MSAL应用
app = msal.ConfidentialClientApplication(
    CLIENT_ID,
    client_credential=CLIENT_SECRET,
    authority=f"https://login.microsoftonline.com/{TENANT_ID}"
)

# 获取令牌
result = app.acquire_token_for_client(scopes=SCOPES)

if "access_token" in result:
    # 构造XOAUTH2认证字符串
    auth_string = f"user={USER_EMAIL}\x01auth=Bearer {result['access_token']}\x01\x01"
    auth_bytes = base64.b64encode(auth_string.encode("utf-8"))
    auth_base64 = auth_bytes.decode("utf-8")

    # 连接IMAP服务器
    imap = imaplib.IMAP4_SSL("outlook.office365.com", 993)
    imap.authenticate("XOAUTH2", lambda x: auth_base64)

    # 后续操作示例
    imap.select("INBOX")
    status, messages = imap.search(None, "ALL")
    print(f"收件箱邮件数量:{len(messages[0].split())}")

    imap.close()
    imap.logout()
else:
    raise Exception(f"获取令牌失败:{result.get('error_description', result.get('error'))}")

关键注意事项

  • 权限范围:IMAP权限对应的是https://outlook.office.com/IMAP.AccessAsUser.All(委派权限),而非Graph的端点,之前误用Graph范围是可能出错的原因之一。
  • 应用注册:公共客户端应用(方案1)无需客户端密钥,但需启用"允许公共客户端流";机密客户端应用(方案2)需生成客户端密钥,并配置对应应用权限。
  • 令牌缓存:MSAL会自动缓存令牌,后续调用acquire_token_silent可直接获取有效令牌,无需重复授权。

内容的提问来源于stack exchange,提问作者federicobaldoni-nextegy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 23:20:18