Microsoft 365 mail with OAuth 2.0¶
Microsoft is retiring basic authentication (mailbox user name and password) for SMTP client submission in Exchange Online. Until the end of December 2026 nothing changes; after that it is disabled by default for existing tenants (administrators can still re-enable it) and the final removal date will be announced in the second half of 2027. New tenants will not have it at all.
Installations that send notifications through smtp.office365.com with authentication: :login
will then stop sending emails. Easy8 Cloud is not affected, it sends through its own mail servers.
Instead of a password, Easy8 can authenticate to smtp.office365.com:587 with an app registration
in Microsoft Entra ID (formerly Azure AD) using the OAuth 2.0 client credentials flow and SMTP
XOAUTH2. No user signs in, nothing is stored in the database and the configuration stays in
config/configuration.yml or environment variables, like any other SMTP setup. Existing
installations need no action until they switch; the new settings are ignored unless configured.
What you need¶
- A Microsoft 365 administrator with the Application Administrator role in Entra ID and a member of the Organization Management role group in Exchange Online.
- The Exchange Online PowerShell
module (
Connect-ExchangeOnline). - A mailbox used as the sender, for example
[email protected]. A shared mailbox works as well. - A tenant in the global Microsoft 365 cloud. US Government (GCC High, DoD) and China (21Vianet) tenants are not supported.
- Outbound connections from the Easy8 server (both
appandsidekiq) tologin.microsoftonline.comover HTTPS and tosmtp.office365.com:587. The HTTPS token request honours thehttps_proxyenvironment variable; SMTP cannot go through a proxy.
1. Register the application¶
- Open the Microsoft Entra admin center › App registrations › New registration.
- Name it, for example Easy8 mail, keep Accounts in this organizational directory only, leave the redirect URI empty and register.
- Note the Application (client) ID and the Directory (tenant) ID from the overview page.
- Under Certificates & secrets create a client secret and copy its value immediately, it is shown only once. Secrets expire after at most 24 months; plan the rotation, otherwise sending stops on the expiry day. Certificate credentials are not supported, so the tenant must allow client secrets.
Do not add any API permissions to the app registration. Access is granted in Exchange Online and limited to the sending mailbox, see below.
2. Grant access to the sending mailbox¶
Find the IDs of the app in Enterprise applications (not App registrations, the Object ID differs) and connect to Exchange Online:
Connect-ExchangeOnline
New-ServicePrincipal -AppId <application-client-id> -ObjectId <enterprise-application-object-id> -DisplayName "Easy8 mail"
New-ManagementScope -Name "Easy8 mail" -RecipientRestrictionFilter "PrimarySmtpAddress -eq '[email protected]'"
New-ManagementRoleAssignment -Name "Easy8 mail SMTP" -App <application-client-id> -Role "Application SMTP.SendAsApp" -CustomResourceScope "Easy8 mail"
Set-CASMailbox -Identity notifications@contoso.com -SmtpClientAuthenticationDisabled $false
Set-CASMailbox enables SMTP AUTH for this one mailbox even when it is disabled for the tenant.
The older setup, the SMTP.SendAsApp API permission with admin consent plus
Add-MailboxPermission -AccessRights FullAccess for the service principal, also works. Never
combine both setups; that ends in 535 5.7.3 Authentication unsuccessful.
Permission changes take 30 minutes to 2 hours to apply in Exchange Online.
3. Configure Easy8¶
Docker¶
Add the variables to .env:
SMTP_HOST=smtp.office365.com
SMTP_PORT=587
SMTP_ENABLE_STARTTLS_AUTO=true
SMTP_AUTHENTICATION=xoauth2
[email protected]
SMTP_MICROSOFT_TENANT_ID=<directory-tenant-id>
SMTP_MICROSOFT_CLIENT_ID=<application-client-id>
SMTP_MICROSOFT_CLIENT_SECRET=<client-secret>
The secret can also be passed as a Docker secret via SMTP_MICROSOFT_CLIENT_SECRET_FILE.
config/configuration.yml¶
production:
email_delivery:
delivery_method: :smtp
smtp_settings:
address: "smtp.office365.com"
port: 587
enable_starttls_auto: true
authentication: :xoauth2
user_name: "[email protected]"
xoauth2_tenant_id: "<directory-tenant-id>"
xoauth2_client_id: "<application-client-id>"
xoauth2_client_secret: "<client-secret>"
| Setting | Environment variable | Description |
|---|---|---|
xoauth2_tenant_id |
SMTP_MICROSOFT_TENANT_ID |
Directory (tenant) ID |
xoauth2_client_id |
SMTP_MICROSOFT_CLIENT_ID |
Application (client) ID |
xoauth2_client_secret |
SMTP_MICROSOFT_CLIENT_SECRET |
Client secret |
user_name is the sending mailbox; password is not used.
Restart both the application server and Sidekiq, then send Administration › Settings › Email
notifications › Send a test email. Errors from Microsoft are shown there and written to
log/easy_mailer.log.
Access tokens are requested on the first email and reused until shortly before they expire, so the app registration needs no other maintenance than renewing its client secret.
Sender addresses¶
Emails are submitted through the configured mailbox. Every other address Easy8 uses as From needs
a Send As permission, otherwise Microsoft rejects the email with
5.7.60 … Client does not have permissions to send as this sender:
- Administration › Settings › Email notifications › Notification email address (FROM): simplest is to set it to the sending mailbox.
- HelpDesk Sender setting: the default Current logged user sends from each user's own address. Default from mail notification keeps the user's name but uses the notification address, so no extra permissions are needed. Mailbox address and the per-project custom sender use the HelpDesk mailbox addresses.
- The sender typed into Send email on a task, DMSF Send documents by email and the automation Send email action.
Grant it for each address that must stay; the trustee is the Exchange service principal:
Add-RecipientPermission -Identity support@contoso.com -Trustee (Get-ServicePrincipal -Identity "Easy8 mail").Identity -AccessRights SendAs
Sent Items and limits¶
Exchange Online stores a copy of every submitted email in the Sent Items folder of the sending
mailbox. Add a retention policy that deletes items from Sent Items after a few days, otherwise the
mailbox fills up and sending stops with 554 5.2.2 mailbox full … QuotaExceededException.
Exchange Online sending limits apply per mailbox:
- 30 messages per minute (excess is delayed, not rejected),
- 10,000 recipients per day and the tenant-wide limit for external recipients,
- 3 concurrent SMTP connections; more parallel Sidekiq workers cause
432 4.3.2 Concurrent connections limit exceededand are retried.
Installations sending more should use a dedicated mail service or an SMTP relay connector (authenticated by the server's static IP address or certificate, no Easy8 change needed).
Troubleshooting¶
| Error | Cause |
|---|---|
Microsoft Entra ID token request failed: invalid_client: AADSTS7000222 |
The client secret expired; create a new one. |
… AADSTS7000215 |
Wrong client secret (the secret ID was used instead of its value). |
… AADSTS90002 / AADSTS700016 |
Wrong tenant ID / client ID. |
535 5.7.3 Authentication unsuccessful |
Missing or not yet applied role assignment, the Object ID from App registrations used in New-ServicePrincipal, both setups combined, or user_name is not the scoped mailbox. |
535 5.7.139 … SmtpClientAuthentication is disabled |
Run Set-CASMailbox … -SmtpClientAuthenticationDisabled $false; with Security defaults enabled in Entra ID, SMTP AUTH may stay blocked. |
5.7.60 |
The From address needs Send As, see Sender addresses. |
Emails sent in the background are retried by Sidekiq, so a temporary Microsoft outage does not lose notifications.