Skip to content

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 app and sidekiq) to login.microsoftonline.com over HTTPS and to smtp.office365.com:587. The HTTPS token request honours the https_proxy environment variable; SMTP cannot go through a proxy.

1. Register the application

  1. Open the Microsoft Entra admin center › App registrations › New registration.
  2. Name it, for example Easy8 mail, keep Accounts in this organizational directory only, leave the redirect URI empty and register.
  3. Note the Application (client) ID and the Directory (tenant) ID from the overview page.
  4. 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 exceeded and 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.