A cloud-based identity and access management service for securing user authentication and resource access
Hello S, Krishnamurthy,
I understand you want to send mails on behalf of users that is, use client credential flow, but you have only delegated API permissions granted to the Microsoft Entra ID application.
To send emails using Microsoft Graph API with the client credentials flow (without user interaction), you need application permissions rather than delegated permissions. Since you are making use of delegated permissions you are getting 403 error.
- Application permissions are used for scenarios where the application acts as itself (i.e., not on behalf of a user).
- For sending emails without user interaction, you need to use the Mail.Send application permission.
- There is no way to use delegated API permission and send mail via client credential flow.
- If you want to use delegated API permission then you have to make use of any user interactive flow only.
Delegated permissions require a signed-in user and allow the app to act on behalf of that user. To send emails without user interaction, you need application permissions (like Mail.Send), which allow the app to act independently of a user and perform actions across the organization.
Initially I granted delegated API permission to send mail using client credential flow and got the same error:

To resolve the error, either you need to switch to any user interactive flow, or you need to grant Mail.Send application permission:
I am able to send mail successfully:
tenant_id = 'TenantID'
client_id = 'ClientID'
client_secret = 'Secret'
scope = 'https://graph.microsoft.com/.default'
grant_type = 'client_credentials'
token_url = f'https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token'
def get_access_token():
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
payload = {
'client_id': client_id,
'client_secret': client_secret,
'scope': scope,
'grant_type': grant_type
}
response = requests.post(token_url, headers=headers, data=payload)
if response.status_code == 200:
token = response.json().get('access_token')
return token
else:
print(f"Error fetching access token: {response.text}")
return None
def send_email(access_token, recipient, subject, body):
send_mail_url = 'https://graph.microsoft.com/v1.0/users/UserID/sendMail'
send_mail_headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json'
}
email_data = {
"message": {
"subject": subject,
"body": {
"contentType": "Text",
"content": body
},
"toRecipients": [
{
"emailAddress": {
"address": recipient
}
}
]
}
}
response = requests.post(send_mail_url, headers=send_mail_headers, json=email_data)
if response.status_code == 202:
print('Email sent successfully!')
else:
print(f"Error sending email: {response.status_code}, {response.text}")
if __name__ == "__main__":
access_token = get_access_token()
if access_token:
recipient = "******@xxx.onmicrosoft.com"
subject = "Test Email"
body = "This is a test email sent using Microsoft Graph API"
send_email(access_token, recipient, subject, body)

Reference:
user: sendMail - Microsoft Graph v1.0 | Microsoft
Hope this helps!
If this answer was helpful, please click "Accept the answer" and mark Yes, as this can be beneficial to other community members.
If you have any other questions or still running into more issues, let me know in the "comments" and I would be happy to help you.