Historically, enterprise applications, multifunction printers, and automated scripts utilized Basic Authentication (a simple username and password) to send emails via Microsoft Exchange Online. However, Basic Authentication is mathematically vulnerable to credential stuffing, password spraying, and interception. Recognizing this severe vulnerability, Microsoft permanently deprecated Basic Authentication for Exchange Online. Applications must now utilize Modern Authentication (OAuth 2.0). If you have a backend Node.js, Python, or C# application that must autonomously send transactional emails via SMTP without human interaction, you cannot use an interactive login. You must configure Authenticated Client SMTP Submission (SMTP AUTH) utilizing the OAuth 2.0 Client Credentials Flow.
The Architecture of the Client Credentials Flow
Unlike the Authorization Code Flow (which requires a human to type a password into a browser popup) or the Resource Owner Password Credentials flow (which is highly discouraged), the Client Credentials Flow operates machine-to-machine.
Your application is registered as an independent cryptographic entity (a Service Principal) within Microsoft Entra ID (formerly Azure AD). The application authenticates to the Entra ID token endpoint utilizing a securely stored Client ID and a cryptographic Client Secret (or preferably, an X.509 certificate).
Entra ID validates these credentials and returns a short-lived JSON Web Token (JWT) Access Token. The application then opens an SMTP connection to smtp.office365.com and injects this JWT into the SMTP AUTH XOAUTH2 protocol sequence. Exchange Online validates the cryptographic signature of the token and permits the email transmission.
Registering the Application in Entra ID
To implement this, you must first establish the Service Principal identity.
- Navigate to the Microsoft Entra admin center.
- Select App registrations > New registration.
- Name the application (e.g.,
Invoice-Email-Service). Select Accounts in this organizational directory only. Leave the Redirect URI blank (it is not required for the Client Credentials flow). - Once created, navigate to Certificates & secrets. Generate a new Client secret. Immediately copy the Secret Value; you will never see it again.
- Navigate to API permissions. This is the critical step. You must grant the application permission to use SMTP. Click Add a permission > APIs my organization uses. Search for Office 365 Exchange Online.
- Select Application permissions (not Delegated permissions). Search for and select
SMTP.SendAsApp. - Because this is an Application permission, it requires global authorization. Click Grant admin consent for [Tenant Name].
Authorizing the Service Principal to a Mailbox
Granting SMTP.SendAsApp allows the application to theoretically send email as any user in the tenant. This is a massive security risk. You must mathematically restrict the application to a specific shared mailbox (e.g., [email protected]) using Exchange Online PowerShell.
Connect to the Exchange Online management shell:
Connect-ExchangeOnline -UserPrincipalName [email protected]
Next, you create a new Service Principal object directly within Exchange Online, linking it to the Entra ID Application ID you created earlier, and assign it FullAccess to the specific mailbox:
$AppId = "YOUR_ENTRA_APP_ID"
$ObjectId = "YOUR_ENTRA_ENTERPRISE_APP_OBJECT_ID"
$TenantId = "YOUR_TENANT_ID"
New-ServicePrincipal -AppId $AppId -ObjectId $ObjectId -Organization $TenantId
Add-MailboxPermission -Identity "[email protected]" -User $ObjectId -AccessRights FullAccess
Note: You must also ensure that SMTP AUTH is explicitly enabled on that specific mailbox, even if it is disabled globally for the tenant.
Executing the XOAUTH2 SMTP Connection
In your application code, you execute a two-step process.
First, execute an HTTP POST request to the Entra ID /token endpoint to acquire the Access Token. The scope must be exactly https://outlook.office365.com/.default.
Once you possess the Access Token string, you format it for the SMTP AUTH XOAUTH2 command. The protocol requires a highly specific base64-encoded payload combining the sender’s email address and the token:
base64("[email protected]^Aauth=Bearer [JWT_ACCESS_TOKEN]^A^A")
(Note: ^A represents the ASCII Control-A character, 0x01).
You inject this base64 string directly into your SMTP library (such as Python’s smtplib or Nodemailer in Node.js) immediately after the STARTTLS negotiation. Exchange validates the token, returning a 235 2.7.0 Authentication successful response. By migrating to the OAuth 2.0 Client Credentials flow, enterprise developers eliminate the catastrophic risks of Basic Authentication while maintaining autonomous, machine-to-machine email capabilities.