Skip to content

Sending Email through Microsoft 365

The m365 transport sends email through the Microsoft Graph API's sendMail action, authenticated with an Entra ID (Microsoft's identity platform) client-credentials OAuth2 grant. It's the transport to reach Microsoft 365 or Exchange Online without speaking SMTP at all — see SMTP if you would rather use Exchange Online's own SMTP AUTH OAuth2 replacement instead.

Profile fields

Field Type Required Default Notes
tenant_id string yes the Entra tenant id
client_id string yes the Entra app registration's client id
client_secret string yes use _env:VAR_NAME — see Keeping Secrets Out of the Database
sender string yes the mailbox to send from, as a user principal name or object id
save_to_sent_items boolean no false whether Graph saves a copy to the sender's Sent Items folder
timeout_seconds integer no 30 (capped at 120)

The token is requested with Graph's fixed .default scope for sendMail and cached until shortly before it expires; a cached token that gets rejected (an HTTP 401) triggers exactly one automatic refresh and retry before the send is given up on.

Message fields

Field Required Notes
to at least one address
cc no
bcc no
reply_to no
subject no
body_text / body_html at least one Graph carries only a single body — see below
attachments no array of {filename, content_type, content_base64}; Graph limits an inline attachment to roughly 3 MB

Unlike the SMTP transport, Graph's message shape has room for only one body. If you supply both body_text and body_html, body_html wins — the plain-text version is simply not sent.

What success means

A 202 Accepted response from Graph is treated as success, and the request's request-id response header becomes the provider reference recorded against the notification. This means Graph has accepted the send request — it is not proof that the message reached, or will reach, the recipient's inbox. Graph's own delivery, filtering, and mailbox rules all still apply after this point, exactly as they would for any other message sent through Microsoft 365.

Failure classification

Graph's 429 (throttling — you're sending too fast) is transient and goes through the normal retry chain, as are 5xx responses and outright network failures. Every other 4xx response — a malformed message, a sender Graph doesn't recognise, a permission Graph has revoked — is a permanent failure, resolved immediately with no retry.


Continue to Sending Email through Azure Communication Services.