前言
除了 Microsoft Graph,Outlook 邮箱也可以通过传统邮件协议读取,例如 IMAP 和 POP3。本文结合一个 Python 示例脚本,说明如何使用 OAuth2 的 access_token 配合 XOAUTH2 认证登录 Outlook 邮箱,并解释这套接入方式背后的原理。
整体流程
这个脚本整体分成三段:
用
refresh_token向微软换取access_token生成
XOAUTH2认证串分别连接 IMAP 和 POP3 服务,读取邮箱数据
对应关系如下:
OAuth2 负责颁发令牌
XOAUTH2 负责把令牌包装成邮件协议可识别的认证格式
IMAP / POP3 负责真正访问邮件服务
第一步:刷新 access_token
脚本先请求微软令牌接口:
import requestsdef get_access_token(refresh_token: str, client_id: str) -> str:
data = { "client_id": client_id, "grant_type": "refresh_token", "refresh_token": refresh_token,
}
resp = requests.post( "https://login.microsoftonline.com/consumers/oauth2/v2.0/token",
data=data,
timeout=15,
)
resp.raise_for_status() return resp.json()["access_token"]这一步和 Graph API 的思路一致:
refresh_token用来续期access_token用来真正访问资源
区别只是后面访问的不是 Graph,而是 IMAP / POP3 服务。
第二步:生成 XOAUTH2 认证串
脚本里有一个很关键的方法:
def generate_auth_string(user: str, token: str) -> str: return f"user={user}\x01auth=Bearer {token}\x01\x01"这里的 \x01 是控制字符 SOH,XOAUTH2 认证内容本质上是一个特殊格式的字符串。服务端收到后,会把其中的:
用户邮箱
Bearer Token
拆出来校验。
第三步:连接 IMAP
原脚本使用 imaplib.IMAP4_SSL 连接 Outlook:
import imaplibdef connect_imap(email_addr: str, access_token: str):
mail = imaplib.IMAP4_SSL("outlook.live.com")
mail.authenticate("XOAUTH2", lambda _: generate_auth_string(email_addr, access_token)) return mail认证成功以后,脚本继续:
选择
INBOX收件箱选择
Junk垃圾箱执行
search(None, 'ALL')再逐封
fetch(..., '(RFC822)')
这里抓到的是完整原始邮件内容,也就是 RFC822 格式报文。
邮件正文是怎么解析出来的
原脚本使用 Python 内置 email 模块解析返回结果:
import emaildef fetch_email_body(mail, item):
status, msg_data = mail.fetch(item, "(RFC822)") for response_part in msg_data: if isinstance(response_part, tuple):
msg = email.message_from_bytes(response_part[1])
subject = msg.get("Subject")
sender = msg.get("From")
...后面又进一步判断:
如果是多部分邮件
multipart就遍历每个 part
找到
text/plain且不是附件的部分再解码正文
这一步其实就是在做 MIME 报文拆解。
为什么比 Graph API 麻烦
因为 IMAP 返回的是原始邮件内容,不是已经整理好的 JSON。开发者必须自己处理:
主题编码
发件人字段
多部分正文
附件判断
字符集解码
也正因如此,传统协议更灵活,但实现成本也更高。
POP3 部分是怎么做的
脚本里的 POP3 连接方式是:
import base64import poplibdef connect_pop3(email_addr: str, access_token: str):
server = poplib.POP3_SSL("outlook.live.com")
auth = generate_auth_string(email_addr, access_token)
encoded = base64.b64encode(auth.encode("utf-8")).decode("utf-8")
server._shortcmd("AUTH XOAUTH2")
server._shortcmd(encoded) return server这里比 IMAP 多了一步 Base64 编码,因为 POP3 的认证交换格式通常需要把认证串编码后发给服务端。
脚本最后调用 server.list() 打印邮件列表,说明连接与认证已经成功。
IMAP 和 POP3 的区别
虽然都能收邮件,但它们适用场景不同:
IMAP
支持文件夹
支持服务端搜索
支持已读、未读、删除等状态同步
更适合做完整邮箱客户端或邮件同步程序
POP3
协议更简单
更偏向“下载邮件”
文件夹和状态能力弱很多
更适合做轻量拉取任务
如果要读取收件箱、垃圾箱、按条件检索、保留服务端状态,IMAP 会更合适。
这类脚本适合什么场景
在合法授权前提下,这类脚本适合:
自建邮件备份工具
企业内部告警邮箱轮询
邮件工单自动分发
兼容旧系统的邮箱同步服务
如果只是读取邮件列表、主题、发件人等基础信息,Graph API 更省事;如果要兼容旧邮件生态、处理原始 MIME、保留传统协议能力,IMAP / POP3 仍然有价值。
原脚本里可以优化的点
1. 敏感信息不要直接打印
原脚本会打印:
响应内容
新 refresh_token
access_token
邮箱地址
这些都不适合保留在正式环境日志里。
2. 字符编码要更稳妥
邮件正文和主题经常存在多种编码,建议:
使用更安全的兜底解码
对异常编码单独处理
不要默认所有正文都能直接
.decode()成功
3. POP3 不建议依赖私有方法
原脚本使用了 server._shortcmd(),这是库的私有方法。测试脚本里能跑,但长期维护时可读性和稳定性都一般,更适合封装成清晰的认证流程。
4. 建议增加超时与错误分类
真实项目里应补上:
请求超时
认证失败
令牌过期
邮箱权限不足
网络抖动重试
总结
这类 Outlook IMAP / POP3 接入脚本,本质上是把现代 OAuth2 令牌体系和传统邮件协议通过 XOAUTH2 连接起来:
微软 OAuth2 负责发令牌
IMAP / POP3 负责提供邮件访问能力
Python
email模块负责解析原始报文
如果你需要兼容传统邮箱协议栈,或者必须处理原始邮件内容,那么这套实现依然很实用。只是相比 Graph API,它更底层,也更考验你对邮件协议和 MIME 结构的理解。


评论列表