[Python] Why do I keep getting "401 unauthorized" response when sending mails through Graph...

Discussão em 'Python' iniciado por Stack, Março 28, 2025.

  1. Stack

    Stack Membro Participativo

    I have created an app on Azure to send emails using Graph API with delegated type access [​IMG]

    I'm using an interactive flow to generate auth code and access token using oauth2/v2.0/authorize and oauth2/v2.0/token endpoints using the following code

    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()


    It seems like the access token that is generated also has all the permissions(scope) i.e., Mail.Send,User.Read [​IMG]

    But, in the end, I got 401 unauthorized error.

    Failed to send email. Status code: 401 <Response [401]>

    I have also set the redirect_uri and supported account type to all accounts [​IMG]

    Do I need to use an Office365 account or I can use any Microsoft account to send and receive emails?

    Edit: Here's the screenshot of the error code and output [​IMG]

    Continue reading...

Compartilhe esta Página