Python使用OAuth2认证Microsoft SMTP发信报535 5.7.3错误如何解决
问题根因定位
你遇到的535 5.7.3认证失败主要来自以下几个高频错误点,按照优先级排序:
- 权限配置类型错误:你在AAD应用中配置的
SMTP.Send权限如果是「应用程序权限」而非「委托权限」,即便已经授权也无法通过SMTP OAuth认证,Office 365 SMTP OAuth仅支持委托权限场景,且必须由租户管理员完成权限同意。 - Exchange Online租户级配置限制:即使单个邮箱开启了SMTP权限,租户默认可能禁用了legacy协议的OAuth访问能力,需要在Exchange管理中心开启对应策略。
- SMTP指令调用顺序/参数错误:你现有代码的SMTP指令流程存在两处错误:
- XOAUTH2认证必须使用
EHLO指令而非HELO,HELO不支持扩展认证协议协商 - 指令执行顺序错误:正确流程应为「建立连接→EHLO→开启STARTTLS→再次EHLO→发起认证」,你现有代码在STARTTLS之后才首次发起HELO,不符合协议要求
- XOAUTH2认证必须使用
- Token发送格式错误:你编码后的XOAUTH2 token发送时未追加
\r\n结束符,部分Office 365节点会将未正确结束的请求视为非法包直接拒绝。
可行解决方案
步骤1:修正AAD应用权限配置
- 进入AAD应用注册页的「API权限」界面,删除原有
SMTP.Send权限 - 重新添加权限:选择「Office 365 Exchange Online」→「委托权限」→搜索勾选
SMTP.Send - 点击「授予管理员同意」完成全局授权
步骤2:检查Exchange Online租户配置
- 进入Exchange管理中心,确认租户级「已启用安全默认值」设置为关闭,安全默认值会直接拦截所有legacy协议的OAuth请求
- 执行Exchange Online PowerShell命令确认SMTP AUTH策略:
Get-TransportConfig | Format-List SmtpClientAuthenticationDisabled
如果返回值为True,执行命令开启:
Set-TransportConfig -SmtpClientAuthenticationDisabled $False
步骤3:修正SMTP认证代码
替换你的MicrosoftSMTP类和调用逻辑为以下版本:
import smtplib import base64 class MicrosoftSMTP(smtplib.SMTP): def __init__(self, host="smtp.office365.com", port=587, **kwargs): super().__init__(host=host, port=port, **kwargs) self.set_debuglevel(True) @staticmethod def encode_auth_token(username, token): auth_str = f"user={username}\x01auth=Bearer {token}\x01\x01" return base64.b64encode(auth_str.encode('utf-8')).decode('ascii') def authenticate(self, username, token): # 首次EHLO协商扩展能力 code, msg = self.ehlo() if code != 250: raise Exception(f"EHLO failed: {msg.decode()}") # 开启TLS后再次EHLO code, msg = self.starttls() if code != 220: raise Exception(f"STARTTLS failed: {msg.decode()}") code, msg = self.ehlo() if code != 250: raise Exception(f"Post-TLS EHLO failed: {msg.decode()}") # 发起XOAUTH2认证 code, msg = self.docmd("AUTH", "XOAUTH2") if code != 334: raise Exception(f"Auth init failed: {msg.decode()}") # 发送token,自动追加\r\n结束符 code, msg = self.docmd(self.encode_auth_token(username, token)) if code != 235: raise Exception(f"Auth failed: {msg.decode()}")
调用逻辑简化为:
@app.route("/send_to_self") def send_to_self(): token = _get_token_from_cache(app_config.SCOPE) if not token: return redirect(url_for("login")) connection = MicrosoftSMTP() try: connection.authenticate( token["id_token_claims"]["preferred_username"], token["access_token"], ) # 此处添加邮件发送逻辑 # connection.sendmail(from_addr, to_addrs, msg.as_string()) finally: connection.quit() return render_template( "send_to_self.html", data=token, data_session=session["flow"], data_user=session["user"], )
步骤4:校验Token有效性
如果上述步骤执行后仍报错,将获取到的access_token粘贴到JWT解析工具中解析,确认aud字段值为https://outlook.office.com,如果是Graph API的受众则说明Scope配置错误,需确认请求Scope为https://outlook.office.com/SMTP.Send。
内容的提问来源于stack exchange,提问作者Tamas
相关产品推荐
相关产品推荐

