I created below app to send mail using Graph API
I used Client Credential flow to send mail, but I keep getting 401 error. Is there anything that needs to be changed in the API permission on Azure or in the code? Is there a way I can send mail using delegated access without an interactive session?
import requests
import msal
client_id = 'bdxxx'
tenant_id = '97xxx'
client_secret = 'Ltxxxxxx'
authority = f'/{tenant_id}'
scope = ['/.default']
graph_url = '.0'
sender_email = '[email protected]'
def get_access_token():
try:
client = msal.ConfidentialClientApplication(client_id, authority=authority, client_credential=client_secret)
token_result = client.acquire_token_for_client(scopes=scope)
if "access_token" in token_result:
return f"Bearer {token_result['access_token']}"
else:
raise Exception(f"Failed to obtain access token: {token_result}")
except Exception as e:
print(f"Exception: {e}")
return None
if __name__ == '__main__':
access_token = get_access_token()
print(f'Access token: {access_token}')
if not access_token:
print("Access token retrieval failed. Exiting.")
exit()
headers = {
'Authorization': access_token,
'Content-Type': 'application/json'
}
email_message = {
"message": {
"subject": "Test Email",
"body": {
"contentType": "HTML",
"content": "Email body"
},
"toRecipients": [
{
"emailAddress": {
"address": "[email protected]"
}
}
],
"from": {
"emailAddress": {
"address": '[email protected]'
}
}
},
"saveToSentItems": "false"
}
response = requests.post(
f"{graph_url}/users/{sender_email}/sendMail",
json=email_message,
headers=headers
)
print(f'{response.status_code} {response.text}')
I created below app to send mail using Graph API
I used Client Credential flow to send mail, but I keep getting 401 error. Is there anything that needs to be changed in the API permission on Azure or in the code? Is there a way I can send mail using delegated access without an interactive session?
import requests
import msal
client_id = 'bdxxx'
tenant_id = '97xxx'
client_secret = 'Ltxxxxxx'
authority = f'https://login.microsoftonline/{tenant_id}'
scope = ['https://graph.microsoft/.default']
graph_url = 'https://graph.microsoft/v1.0'
sender_email = '[email protected]'
def get_access_token():
try:
client = msal.ConfidentialClientApplication(client_id, authority=authority, client_credential=client_secret)
token_result = client.acquire_token_for_client(scopes=scope)
if "access_token" in token_result:
return f"Bearer {token_result['access_token']}"
else:
raise Exception(f"Failed to obtain access token: {token_result}")
except Exception as e:
print(f"Exception: {e}")
return None
if __name__ == '__main__':
access_token = get_access_token()
print(f'Access token: {access_token}')
if not access_token:
print("Access token retrieval failed. Exiting.")
exit()
headers = {
'Authorization': access_token,
'Content-Type': 'application/json'
}
email_message = {
"message": {
"subject": "Test Email",
"body": {
"contentType": "HTML",
"content": "Email body"
},
"toRecipients": [
{
"emailAddress": {
"address": "[email protected]"
}
}
],
"from": {
"emailAddress": {
"address": '[email protected]'
}
}
},
"saveToSentItems": "false"
}
response = requests.post(
f"{graph_url}/users/{sender_email}/sendMail",
json=email_message,
headers=headers
)
print(f'{response.status_code} {response.text}')
Share
Improve this question
asked Mar 27 at 12:13
Lucifer DarknightLucifer Darknight
495 bronze badges
1
- To resolve the issue you need to assign Mail.Send application type API permission – Rukmini Commented Mar 27 at 12:24
1 Answer
Reset to default 1The error usually occurs if you using ConfidentialClientApplication
to send mail and granted delegated type API permission to the Microsoft Entra ID application.
Hence to resolve the error, you need to grant application type API permission to the Microsoft Entra ID application. Refer this MsDoc
Make sure to grant admin consent:
Now I am able to send mail successfully:
import requests
import msal
client_id = 'ClientID'
tenant_id = 'TenantID'
client_secret = 'Secret'
authority = f'https://login.microsoftonline/{tenant_id}'
scope = ['https://graph.microsoft/.default']
graph_url = 'https://graph.microsoft/v1.0'
sender_email = 'xxx'
def get_access_token():
try:
client = msal.ConfidentialClientApplication(client_id, authority=authority, client_credential=client_secret)
token_result = client.acquire_token_for_client(scopes=scope)
if "access_token" in token_result:
return f"Bearer {token_result['access_token']}"
else:
raise Exception(f"Failed to obtain access token: {token_result}")
except Exception as e:
print(f"Exception: {e}")
return None
if __name__ == '__main__':
access_token = get_access_token()
print(f'Access token: {access_token}')
if not access_token:
print("Access token retrieval failed. Exiting.")
exit()
headers = {
'Authorization': access_token,
'Content-Type': 'application/json'
}
email_message = {
"message": {
"subject": "Test Email",
"body": {
"contentType": "HTML",
"content": "Email body"
},
"toRecipients": [
{
"emailAddress": {
"address": "xxx"
}
}
],
"from": {
"emailAddress": {
"address": 'xxx'
}
}
},
"saveToSentItems": "false"
}
response = requests.post(
f"{graph_url}/users/{sender_email}/sendMail",
json=email_message,
headers=headers
)
print(f'{response.status_code} {response.text}')
- Make sure to assign
O365 license
to the user. - And if you are making use of personal Microsoft user account to send mail, then it required
Mail.Send
delegated API permission which doesn't work withConfidentialClientApplication
- For personal Microsoft user account, you need to make use of
/me
that ishttps://graph.microsoft/v1.0/me/sendMail
endpoint and make use of any user interactive flow.