需要身份验证令牌时从Python发送Exchange邮件的最佳方式
实现方案
推荐两种可行的实现方式,可根据业务场景选择:
方案1:使用smtplib配合OAuth2认证(你之前误以为smtplib不支持,实际可以通过自定义认证逻辑实现)
前置要求
- 应用注册时已添加
Office 365 Exchange Online的SMTP.SendAsApp应用权限,且已获得租户管理员同意 - 获取令牌时的scopes参数填写为
["https://outlook.office365.com/.default"]
代码示例
import msal import smtplib import base64 from email.mime.text import MIMEText # 1. 获取令牌(和你现有逻辑一致,注意scope正确) param_client_id = "你的客户端ID" param_client_credential = "你的客户端凭证" param_tenant_name = "你的租户ID/域名" scopes = ["https://outlook.office365.com/.default"] sender_email = "发件人邮箱地址" app = msal.ConfidentialClientApplication( client_id=param_client_id, client_credential=param_client_credential, authority=f"https://login.microsoftonline.com/{param_tenant_name}" ) result = app.acquire_token_for_client(scopes=scopes) mytoken = result['access_token'] # 2. 构造XOAuth2认证字符串 auth_string = f"user={sender_email}\x01auth=Bearer {mytoken}\x01\x01" auth_string_b64 = base64.b64encode(auth_string.encode('utf-8')).decode('utf-8') # 3. 构造邮件内容 msg = MIMEText("邮件正文内容", "plain", "utf-8") msg['From'] = sender_email msg['To'] = "收件人邮箱地址" msg['Subject'] = "邮件主题" # 4. SMTP连接发送 with smtplib.SMTP("smtp.office365.com", 587) as server: server.starttls() # 不用默认的login方法,手动发送XOAuth2认证命令 server.docmd("AUTH", f"XOAUTH2 {auth_string_b64}") server.sendmail(sender_email, ["收件人邮箱地址"], msg.as_string())
方案2:调用Microsoft Graph API发送邮件(官方推荐,无需维护SMTP连接逻辑)
前置要求
- 应用注册时已添加
Microsoft Graph的Mail.Send应用权限,且已获得租户管理员同意 - 获取令牌时的scopes参数填写为
["https://graph.microsoft.com/.default"]
代码示例
import msal import requests # 1. 获取令牌 param_client_id = "你的客户端ID" param_client_credential = "你的客户端凭证" param_tenant_name = "你的租户ID/域名" scopes = ["https://graph.microsoft.com/.default"] sender_email = "发件人邮箱地址" app = msal.ConfidentialClientApplication( client_id=param_client_id, client_credential=param_client_credential, authority=f"https://login.microsoftonline.com/{param_tenant_name}" ) result = app.acquire_token_for_client(scopes=scopes) mytoken = result['access_token'] # 2. 构造发邮件请求参数 url = f"https://graph.microsoft.com/v1.0/users/{sender_email}/sendMail" headers = { "Authorization": f"Bearer {mytoken}", "Content-Type": "application/json" } payload = { "message": { "subject": "邮件主题", "body": { "contentType": "Text", "content": "邮件正文内容" }, "toRecipients": [ { "emailAddress": { "address": "收件人邮箱地址" } } ] }, "saveToSentItems": True # 是否保存到发件箱 } # 3. 发送请求 response = requests.post(url, headers=headers, json=payload) response.raise_for_status() # 异常校验
常见问题排查
- 确认应用注册的权限类型为应用权限而非委托权限,且已经过管理员同意
- 确认获取的令牌权限正确,可解析令牌查看
roles声明是否包含对应权限 - 若使用SMTP方案,确认发件人账户已开启
Authenticated SMTP选项(你已配置可忽略)
内容的提问来源于stack exchange,提问作者MartinHN
相关产品推荐
相关产品推荐

