Entra ID Setup¶
The relay authenticates to Microsoft Graph with the OAuth 2.0 client credentials flow. You need one Entra ID application registration that provides:
| Component | Purpose |
|---|---|
| Application (client) ID + Tenant ID | Form the SMTP username |
| Client secret | The SMTP password |
Application Mail.Send role assignment, scoped to a mailbox (recommended) |
Grants send rights and limits which mailboxes the app can send from |
How send rights are granted
With RBAC for Applications (recommended) you do not add the Mail.Send Graph application permission to the app registration. Send rights come solely from the Exchange New-ManagementRoleAssignment below, scoped to a management scope — so the app can only send from the mailboxes in that scope.
Only grant the tenant-wide Mail.Send Graph application permission if you deliberately want the app to send from any mailbox (the -AllMailboxes path).
Recommended: the setup script¶
New-RelayEntraApp.ps1 performs the entire setup: registers the app, creates a secret and service principal, and grants scoped send rights via RBAC.
Prerequisites¶
- PowerShell 5.1+
- Roles: Application Administrator (Graph) and Exchange Administrator (skip Exchange with
-AllMailboxes) - Modules and active sessions:
Install-Module Microsoft.Graph -Scope CurrentUser
Install-Module ExchangeOnlineManagement -Scope CurrentUser # not needed with -AllMailboxes
Connect-MgGraph -Scopes "Application.ReadWrite.All", "AppRoleAssignment.ReadWrite.All" -NoWelcome
Connect-ExchangeOnline -ShowBanner:$false
Run it¶
Invoke-WebRequest `
-Uri "https://raw.githubusercontent.com/JustinIven/smtp-oauth-relay/main/New-RelayEntraApp.ps1" `
-OutFile "New-RelayEntraApp.ps1"
# Restricted to one sender (recommended)
.\New-RelayEntraApp.ps1 -DisplayName "SMTP OAuth Relay" -SenderAddress "noreply@example.com"
Other invocations
# Allow any mailbox — trusted/isolated tenants only (grants tenant-wide Mail.Send)
.\New-RelayEntraApp.ps1 -DisplayName "SMTP OAuth Relay" -AllMailboxes
# Capture the result for automation
$app = .\New-RelayEntraApp.ps1 -DisplayName "SMTP Relay - HR" -SenderAddress "hr@example.com"
$app.SmtpUsername
$app.SmtpPassword
Parameters¶
| Parameter | Required | Default | Description |
|---|---|---|---|
-DisplayName |
No | SMTP OAuth Relay |
App registration display name |
-SenderAddress |
Yes* | – | Mailbox the app may send from. *Required unless -AllMailboxes |
-SecretValidYears |
No | 2 |
Client secret lifetime in years (0–2) |
-AllMailboxes |
No | off | Skip sender restriction; grant tenant-wide Mail.Send |
-ScopeName |
No | <DisplayName> mailbox scope |
Exchange management scope name |
-TenantId |
No | current session | Tenant ID used to build the SMTP username |
-DisableSummaryOutput |
No | off | Suppress printed summary (object still returned) |
The script prints the SMTP username (tenant_id@client_id) and SMTP password (client secret).
Save the secret now
The client secret is shown only at creation time and cannot be retrieved later.
Manual setup (Azure Portal)¶
Use this only if you cannot run the script.
1. Register the application
- Entra admin center → App registrations → New registration
- Name it, select Accounts in this organizational directory only, leave Redirect URI blank → Register
- From Overview, copy the Application (client) ID and Directory (tenant) ID
2. Create a client secret
- Certificates & secrets → New client secret
- Set a description and expiry (12–24 months) → Add
- Copy the secret Value immediately — it is your SMTP password and cannot be retrieved later
After this, grant scoped send rights. Do not add the Mail.Send API permission on the app registration — the management role assignment grants it instead.
Restrict the sender (recommended)¶
Grant the app the Application Mail.Send role, scoped to a mailbox, with RBAC for Applications in Exchange Online. This is what gives the app permission to send — no app-level Mail.Send API permission or admin consent is required.
Connect-ExchangeOnline
$appId = "<application-client-id>"
New-ManagementScope -Name "SMTP relay scope" `
-RecipientRestrictionFilter "UserPrincipalName -eq 'noreply@example.com'"
New-ServicePrincipal -AppId $appId -ObjectId "<service-principal-object-id>" -DisplayName "SMTP OAuth Relay"
New-ManagementRoleAssignment -App $appId -Role "Application Mail.Send" `
-CustomResourceScope "SMTP relay scope"
To allow a group of mailboxes, point -RecipientRestrictionFilter at a group membership filter, e.g. MemberOfGroup -eq '<group-DN>'.
Note
Role assignments can take 15–30 minutes to propagate.
Legacy: Application Access Policy
Older tenants may still use Application Access Policies (superseded by RBAC for Applications). This approach does require the tenant-wide Mail.Send Graph application permission with admin consent, then restricts it:
New-ApplicationAccessPolicy -AppId $appId `
-PolicyScopeGroupId "sender@example.com" `
-AccessRight RestrictAccess `
-Description "SMTP Relay - restrict sender"
# Test
Test-ApplicationAccessPolicy -AppId $appId -Identity "sender@example.com"
# List / remove
Get-ApplicationAccessPolicy | Format-Table AppId, PolicyScopeGroupId, AccessRight
Remove-ApplicationAccessPolicy -Identity $appId
Multiple applications¶
Create one app per environment, department, or sender to keep credentials and sending scopes isolated. Each app is a separate SMTP username/password pair.