Sending Email through Azure Communication Services¶
The acs transport sends email through Azure Communication Services' own REST API (emails:send), authenticated with an Entra ID (Microsoft's identity platform) client-credentials OAuth2 grant. See SMTP for the alternative path into the same service — Azure Communication Services also offers an SMTP relay, reachable through the SMTP transport's oauth2 authentication mode.
Profile fields¶
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
endpoint |
string | yes | — | your resource's endpoint, e.g. https://my-resource.communication.azure.com; a trailing slash is stripped automatically |
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 |
from |
string | yes | — | the sender address, which must be a verified sender on the Azure Communication Services resource |
timeout_seconds |
integer | no | 30 (capped at 120) |
The token is requested with the Azure Communication Services scope for sending email, from the same token cache shared by every Entra-authenticated transport (m365, and the SMTP transport's oauth2 mode); it's keyed on (tenant_id, client_id, scope), so it is only ever reused by another profile requesting that exact combination. 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 | unlike the Microsoft 365 transport, both are sent together when both are supplied — see below |
attachments |
no | array of {filename, content_type, content_base64} |
Unlike the m365 transport, which carries only a single body and picks HTML when both are supplied, the acs transport populates the request's plainText field from body_text and its html field from body_html, sending both when both are present.
What success means¶
A 202 Accepted response is treated as a successful send, and the operation id parsed from the response body ({"id": "...", "status": "Running"}) becomes the provider reference recorded against the notification. As with Microsoft 365's Graph API, this means Azure Communication Services has accepted the send request for asynchronous processing — it is not proof of delivery. The Processor does not poll for the operation's eventual outcome; if you need to know what happened after acceptance, use the recorded operation id to look the send up in Azure yourself.
Failure classification¶
A 429 response (throttling) is transient and goes through the normal retry chain, as are 5xx responses and outright network failures. Every other 4xx response — a malformed message, an unverified sender domain, a permission Azure Communication Services has revoked — is a permanent failure, resolved immediately with no retry.
Continue to Sending Email through Gmail.