Search code examples
pythonazuremicrosoft-graph-apiaccess-token

Wrong Token on the send mail API on microsoft graph


I'm trying to use the send mail API using the Microsoft Graph API and I've tried it using the Graph API explorer and it's working fine but when I try to get the Token on Postman and get the token I get an error. when I use the token from the explorer on my code it works fine but when using mine from Postman I got this error :

Response content: b'{"error":{"code":"BadRequest","message":"/me request is only valid with delegated authentication flow.","innerError":{"date":"2024-05-28T11:34:23","request-id":"","client-request-id":""}}}'

import requests

url = 'https://graph.microsoft.com/v1.0/me/sendMail'

access_token = ''

headers = {
  'Authorization': 'Bearer {}'.format(access_token),
  'Content-Type': 'application/json'
}

email = {
   "message": {
       "subject": "PYTHON",
       "body": {
          "contentType": "HTML",
          "content": ""
    },
    "toRecipients": [
        {
            "emailAddress": {
                "address": "hamzaha@watira.ai"
            }
        }
    ]
},
"saveToSentItems": "true"
}
response = requests.post(url, headers=headers, json=email)

if response.status_code == 202:
   print("Email sent successfully.")
else:
  print("Failed to send email. Status code:", response.status_code)
  print("Response content:", response.content)

enter image description here

enter image description here


Solution

  • The error occurred as /me endpoint supports only delegated flows like authorization code flow that involves user interaction, but client credentials is app-only flow.

    Initially, I too got same error when I run the code passing token generated with client credentials flow like this:

    import requests
    
    url = 'https://graph.microsoft.com/v1.0/me/sendMail'
    access_token = 'token'
    
    headers = {
      'Authorization': 'Bearer {}'.format(access_token),
      'Content-Type': 'application/json'
    }
    
    email = {
       "message": {
           "subject": "PYTHON",
           "body": {
              "contentType": "HTML",
              "content": ""
        },
        "toRecipients": [
            {
                "emailAddress": {
                    "address": "sridevi.mxxx1@gmail.com"
                }
            }
        ]
    },
    "saveToSentItems": "true"
    }
    response = requests.post(url, headers=headers, json=email)
    
    if response.status_code == 202:
       print("Email sent successfully.")
       
    else:
      print("Failed to send email. Status code:", response.status_code)
      print("Response content:", response.content)
    

    Response:

    enter image description here

    To resolve the error, you need to either switch to delegated flows like authorization code flow for generating token or use /users/userID endpoint with client credentials token.

    In my case, I granted Mail.Send permission of Application type in my app registration like this:

    enter image description here

    Now, I generated token using client credentials flow via Postman as below:

    POST https://login.microsoftonline.com/tenantId/oauth2/v2.0/token
    
    grant_type:client_credentials
    client_id: appId
    client_secret: secret
    scope: https://graph.microsoft.com/.default
    

    Response:

    enter image description here

    When I used this token in below Python code by changing endpoint to /users/userID, I got response like this:

    import requests
    
    url = 'https://graph.microsoft.com/v1.0/users/userId/sendMail'
    access_token = 'token'
    
    headers = {
      'Authorization': 'Bearer {}'.format(access_token),
      'Content-Type': 'application/json'
    }
    
    email = {
       "message": {
           "subject": "PYTHON",
           "body": {
              "contentType": "HTML",
              "content": ""
        },
        "toRecipients": [
            {
                "emailAddress": {
                    "address": "sridevi.mxxx1@gmail.com"
                }
            }
        ]
    },
    "saveToSentItems": "true"
    }
    response = requests.post(url, headers=headers, json=email)
    
    if response.status_code == 202:
       print("Email sent successfully.")
       
    else:
      print("Failed to send email. Status code:", response.status_code)
      print("Response content:", response.content)
    

    Response:

    enter image description here

    You can find User ID of sender in Azure Portal like this:

    enter image description here

    This /me endpoint works in Graph Explorer as it uses delegated permissions of signed-in user. If you prefer switching to delegated flows for generating tokens, refer this similar SO thread I previously answered that includes token generation with authorization code flow:

    azure active directory - Call microsoft graph - Stack Overflow