如何通过Microsoft Graph API发送Python email.message.EmailMessage邮件
如何通过Microsoft Graph API发送Python EmailMessage构建的带嵌入图片的邮件
你的错误源于误用了Graph API的普通邮件发送格式——EmailMessage生成的是完整的多部分MIME邮件内容,不能直接塞进Body.Content字段,需要使用Graph API的MIME邮件发送能力来处理。
错误原因解析
你当前代码将EmailMessage转成字符串后,试图以text/plain的类型传递给Graph API,但这个字符串包含了HTML、嵌入图片等多部分MIME结构,Graph API无法识别这种格式,因此抛出"Requested value 'text/plain' was not found"错误。
解决方案步骤
要发送用EmailMessage构建的邮件,需按以下步骤操作:
- 将
EmailMessage对象序列化为RFC 822格式的字节流 - 对字节流进行Base64编码
- 调用Graph API的
sendMail接口,将编码后的内容放在MimeContent字段中,替代原来的Body字段
修正后的完整代码
import smtplib from email.utils import formatdate from email.message import EmailMessage from email.mime.guess_type import guess_type import requests import msal import base64 server = 'smtp.office365.com' port = 587 from_mail = 'levrai@ninjane.er' to_mail = 'desti@nati.on' subject = 'Demo sending via Graph API!' password = 'not_so_Secur3!' message_parts = ['Hi sir', 'This is a demo message.', 'It could help others to help me, and possibly others too.'] # 假设doc_mail_from_template是已实现的函数,返回文本、HTML内容、图片CID和本地路径 text_msg, html_msg, cids, locs = doc_mail_from_template(message_parts) msg = EmailMessage() msg.set_content(text_msg) # 修正原代码变量名错误:text_message -> text_msg msg.add_alternative(html_msg, subtype='html') msg['From'] = from_mail msg['To'] = to_mail msg['Date'] = formatdate(localtime=True) msg['Subject'] = subject # 嵌入图片到邮件 for loc, cid in zip(locs, cids): with open(loc, 'rb') as img: maintype, subtype = guess_type(img.name)[0].split('/') msg.get_payload()[1].add_related(img.read(), maintype=maintype, subtype=subtype, cid=cid) # 使用Graph API发送邮件 client_id = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx8c5' client_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxb96' tenant_id = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx973' userId = "levrai@ninjane.er" authority = f"https://login.microsoftonline.com/{tenant_id}" scopes = ["https://graph.microsoft.com/.default"] app = msal.ConfidentialClientApplication(client_id=client_id, client_credential=client_secret, authority=authority) result = app.acquire_token_silent(scopes, account=None) if not result: result = app.acquire_token_for_client(scopes=scopes) # 将EmailMessage转为RFC 822格式字节流,再Base64编码 mime_content = msg.as_bytes() base64_mime = base64.b64encode(mime_content).decode('utf-8') # 构造Graph API请求体:使用MimeContent替代Body email_msg = { 'Message': { 'MimeContent': { 'ContentType': 'message/rfc822', 'Content': base64_mime }, 'ToRecipients': [{'EmailAddress': {'Address': to_mail}}] }, 'SaveToSentItems': 'true' } endpoint = f"https://graph.microsoft.com/v1.0/users/{userId}/sendMail" # 修正原代码变量名:from_user -> userId r = requests.post( endpoint, json=email_msg, headers={'Authorization': 'Bearer ' + result['access_token'], "Content-Type": "application/json"} ) # 检查请求结果 if r.status_code == 202: print("邮件发送成功") else: print(f"发送失败,错误信息:{r.text}")
关键注意事项
- 权限配置:确保你的Azure AD应用已添加
Mail.Send应用权限,并完成管理员同意 - 变量修正:原代码中存在
text_message、e_message、from_user等变量名错误,需修正为正确的变量 - Base64编码:必须使用标准Base64编码(无换行符),
base64.b64encode默认符合要求
内容的提问来源于stack exchange,提问作者levraininjaneer
相关产品推荐
相关产品推荐

