使用Python调用Microsoft Graph API发邮件遇权限拒绝及令牌缓存问题
问题描述
使用Python代码调用Microsoft Graph API发送邮件时出现权限拒绝错误,但Postman中可成功发送,不清楚哪里配置缺失。
代码示例
import json import msal import requests client_id = '6c762**************' client_secret = 'F-S**************************' tenant_id = 'e*****************************' authority = f"https://login.microsoftonline.com/{tenant_id}" app = msal.ConfidentialClientApplication( client_id=client_id, client_credential=client_secret, authority=authority) scopes = ["https://graph.microsoft.com/.default"] result = None result = app.acquire_token_silent(scopes, account=None) if not result: print( "No suitable token exists in cache. Let's get a new one from Azure Active Directory.") result = app.acquire_token_for_client(scopes=scopes) # if "access_token" in result: # print("Access token is " + result["access_token"]) if "access_token" in result: userId = "support@****.com" endpoint = f'https://graph.microsoft.com/v1.0/users/{userId}/sendMail' toUserEmail = "hi****@gmail.com" email_msg = {'Message': {'Subject': "Test Sending Email from Python", 'Body': {'ContentType': 'Text', 'Content': "This is a test email."}, 'ToRecipients': [{'EmailAddress': {'Address': toUserEmail}}] }, 'SaveToSentItems': 'true'} r = requests.post(endpoint, headers={'Authorization': 'Bearer ' + result['access_token']}, json=email_msg) if r.ok: print('Sent email successfully') else: print(r.json()) else: print(result.get("error")) print(result.get("error_description")) print(result.get("correlation_id"))
错误信息
缓存中无合适令牌,将从Azure Active Directory获取新令牌。 {'error': {'code': 'ErrorAccessDenied', 'message': '访问被拒绝,请检查凭据并重试。'}}
排查与解决
Postman能成功发送,说明API本身可用,问题出在Python代码的权限配置或认证环节,按以下步骤排查:
- 确认权限类型与配置:代码用的是客户端凭证模式(
acquire_token_for_client),必须在Azure AD应用注册中配置应用权限的Mail.Send,并且完成管理员同意。如果Postman用的是委派权限(比如账号密码登录),两种模式权限要求不同,这是核心差异点。 - 检查权限生效状态:登录Azure AD后台,找到你的应用注册,进入“权限”页面,确保
Mail.Send(应用权限)的状态是“已授予管理员同意”。 - 验证令牌权限:获取到
access_token后,解析令牌查看roles字段是否包含Mail.Send。如果没有,说明权限配置未生效,重新配置后等待几分钟再测试。 - 核对凭证信息:确保代码中的
client_id、client_secret、tenant_id和Postman中使用的完全一致,无字符遗漏或输入错误。 - 确认用户账号有效性:代码中指定的
userId(support@****.com)必须是租户内的有效邮箱账号,且应用权限允许代表该账号发送邮件。
内容的提问来源于stack exchange,提问作者Hietsh Kumar
相关产品推荐
相关产品推荐

