使用Graph API与Office365-REST-Python-Client发邮件报错求助
问题修复与替代实现方案
错误原因分析
你遇到的TypeError是因为:
send_mail()方法不接受subject、body这类直接关键字参数,需要传入完整的邮件消息结构(对象或字典)- 你使用的是客户端凭据流(应用权限),这种模式下不能用
client.me,必须指定具体的发送者邮箱(因为没有用户上下文)
修复后的Office365-REST-Python-Client代码
方式1:使用库内置对象构造邮件
import msal from office365.graph_client import GraphClient from office365.outlook.mail.message import Message from office365.outlook.mail.item_body import ItemBody from office365.outlook.mail.recipient import Recipient from office365.outlook.mail.email_address import EmailAddress # 替换为你的实际配置 config = { 'client_id': 'foo', 'secret': 'bar', 'tenant_id': 'etc', 'sender_email': 'your-sender@company.com' # 必须指定发送者邮箱 } def acquire_token(): authority_url = f'https://login.microsoftonline.com/{config["tenant_id"]}' app = msal.ConfidentialClientApplication( authority=authority_url, client_id=config["client_id"], client_credential=config["secret"] ) token = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"]) return token client = GraphClient(acquire_token) # 构造邮件消息对象 message = Message(client) message.subject = "Meet for lunch?" message.body = ItemBody(content="The new cafeteria is open.", content_type="Text") message.to_recipients = [ Recipient(EmailAddress(email_address="elon.musk@company.com", name="Elon Musk")) ] # 调用发送接口 client.users[config['sender_email']].send_mail(message, save_to_sent_items=True).execute_query()
方式2:用字典直接传递邮件结构(更简洁)
import msal from office365.graph_client import GraphClient config = { 'client_id': 'foo', 'secret': 'bar', 'tenant_id': 'etc', 'sender_email': 'your-sender@company.com' } def acquire_token(): authority_url = f'https://login.microsoftonline.com/{config["tenant_id"]}' app = msal.ConfidentialClientApplication( authority=authority_url, client_id=config["client_id"], client_credential=config["secret"] ) token = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"]) return token client = GraphClient(acquire_token) # 定义邮件结构字典 mail_msg = { "subject": "Meet for lunch?", "body": { "contentType": "Text", "content": "The new cafeteria is open." }, "toRecipients": [ { "emailAddress": { "address": "elon.musk@company.com" } } ] } client.users[config['sender_email']].send_mail(mail_msg, save_to_sent_items=True).execute_query()
不依赖第三方库的原生REST实现
如果不想用office365-rest-python-client,可以直接调用Graph API的REST接口:
import msal import requests config = { 'client_id': 'foo', 'secret': 'bar', 'tenant_id': 'etc', 'sender_email': 'your-sender@company.com' } def get_access_token(): authority = f"https://login.microsoftonline.com/{config['tenant_id']}" app = msal.ConfidentialClientApplication( config['client_id'], authority=authority, client_credential=config['secret'] ) result = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"]) return result['access_token'] # 获取令牌并发送邮件 token = get_access_token() graph_url = f"https://graph.microsoft.com/v1.0/users/{config['sender_email']}/sendMail" headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json" } payload = { "message": { "subject": "Meet for lunch?", "body": { "contentType": "Text", "content": "The new cafeteria is open." }, "toRecipients": [ { "emailAddress": { "address": "elon.musk@company.com" } } ] }, "saveToSentItems": "true" } response = requests.post(graph_url, headers=headers, json=payload) response.raise_for_status() # 抛出请求异常 print("邮件发送成功")
额外注意事项
- 确保你的Azure AD应用已经添加了
Mail.Send的应用权限,并且管理员已完成权限同意 - 应用权限模式下,发送者邮箱必须是租户内的有效邮箱账号
内容的提问来源于stack exchange,提问作者Vitamin C
相关产品推荐
相关产品推荐

