使用Graph API委托权限发送邮件时持续触发401 Unauthorized错误的排查求助
我在Azure上创建了一个应用,想用Graph API的委托权限来实现邮件发送功能,目前采用交互式流程,通过oauth2/v2.0/authorize和oauth2/v2.0/token端点获取授权码和访问令牌,应用注册的配置如下:

以下是我实现整个流程的Python代码:
import requests import webbrowser import urllib.parse class GraphEmailSender: def __init__(self, client_id, tenant_id): """ Initialize Graph Email Sender :param client_id: Azure AD application client ID :param tenant_id: Azure AD tenant ID """ self.client_id = client_id self.tenant_id = tenant_id # OAuth endpoints self.authorize_url = f'https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/authorize' self.token_url = f'https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token' # Graph API endpoint self.graph_endpoint = 'https://graph.microsoft.com/v1.0' # Redirect URI (must be registered in Azure AD app) self.redirect_uri = 'http://localhost:8000/callback' # Scopes for email sending self.scopes = [ 'https://graph.microsoft.com/Mail.Send', 'https://graph.microsoft.com/User.Read', 'offline_access' ] def get_authorization_code(self): """ Generate authorization URL and prompt for manual code entry :return: Authorization code """ # Prepare authorization request parameters auth_params = { 'client_id': self.client_id, 'response_type': 'code', 'redirect_uri': self.redirect_uri, 'scope': ' '.join(self.scopes), 'response_mode':'fragment' } # Construct authorization URL auth_url = f"{self.authorize_url}?{urllib.parse.urlencode(auth_params)}" # Open browser for authorization print("Please authorize the application:") webbrowser.open(auth_url) # Manually enter authorization code auth_code = input("Enter the authorization code from the redirect URL: ") return auth_code def exchange_code_for_token(self, authorization_code): """ Manually exchange authorization code for access token :param authorization_code: Authorization code :return: Access token """ # Prepare token exchange parameters token_params = { 'client_id': self.client_id, 'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': self.redirect_uri, 'scope': ' '.join(self.scopes), 'client_secret':'Ixxxx' } # Send token request response = requests.post( self.token_url, data=token_params, headers={'Content-Type': 'application/x-www-form-urlencoded'} ) # Return access token return response.json().get('access_token') def send_email(self, access_token, to_email, subject, body): """ Send email using access token :param access_token: OAuth access token :param to_email: Recipient email address :param subject: Email subject :param body: Email body :return: Boolean indicating success """ # Prepare email message email_message = { "message": { "subject": subject, "body": { "contentType": "Text", "content": body }, "toRecipients": [ { "emailAddress": { "address": to_email } } ], "from":{ "emailAddresss":{ "address":"lxxx1@gmail.com" } } }, "saveToSentItems": "true" } # Prepare headers headers = { 'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json' } try: # Send email via Graph API response = requests.post( f'{self.graph_endpoint}/me/sendMail', json=email_message, headers=headers ) # Check response if response.status_code in [200, 201, 202]: print("Email sent successfully!") return True else: print(f"Failed to send email. Status code: {response.status_code} {response}") return False except Exception as e: print(f"Error sending email: {e}") return False # Example usage def main(): # Replace with your actual Azure AD application details TENANT_ID = '97sss' CLIENT_ID = '803csss' # Create email sender email_sender = GraphEmailSender(CLIENT_ID, TENANT_ID) # Get authorization code (manual process) auth_code = email_sender.get_authorization_code() # Exchange code for access token access_token = email_sender.exchange_code_for_token(auth_code) # Send email email_sender.send_email( access_token, to_email='gagsgdg@gmail.com', subject='OAuth Email Test', body='Email sent using simplified OAuth flow.' ) if __name__ == '__main__': main()
我检查了生成的访问令牌,确认其中已经包含了所需的权限(Mail.Send、User.Read),JWT解析后的结果如下:

但调用/me/sendMail接口时,始终返回401 Unauthorized,错误信息为:
Failed to send email. Status code: 401 <Response [401]>
我已经在Azure应用中配置了正确的重定向URI,并且将支持的账户类型设置为“所有账户”:

补充完整的错误输出截图:

现在有个疑问:是不是必须使用Office365账户才能通过这种方式发送邮件?还是任何微软账户(比如个人Outlook/Hotmail账户)都可以?另外有没有其他配置或代码问题导致了这个401错误?麻烦各位帮忙排查一下,非常感谢!
备注:内容来源于stack exchange,提问作者Lucifer Darknight




