SMTP OAuth Relay
June 18, 2026 · View on GitHub
A small, stateless SMTP server that lets legacy clients (printers, NAS, monitoring tools, line-of-business apps) send mail through Microsoft 365 using OAuth 2.0 client credentials and the Microsoft Graph API — no Basic Authentication required.
- OAuth 2.0 client credentials — app credentials instead of user passwords
- Microsoft Graph — sends via the
sendMailendpoint - SMTP compatible — any client supporting
AUTH LOGIN/PLAIN+ STARTTLS - Stateless — scale horizontally behind a load balancer
- TLS from file or Azure Key Vault
- Azure Tables — optional central credential lookup
📖 Full documentation: https://justiniven.github.io/smtp-oauth-relay/
Quick start
Three steps. You need a Microsoft 365 tenant and permission to register an Entra ID application.
1. Create Entra ID credentials (PowerShell)
New-RelayEntraApp.ps1 registers the app, creates a secret, and restricts it to a single sender mailbox.
# Prerequisites: PowerShell 5.1+, Microsoft.Graph and ExchangeOnlineManagement modules
Connect-MgGraph -Scopes "Application.ReadWrite.All", "AppRoleAssignment.ReadWrite.All" -NoWelcome
Connect-ExchangeOnline -ShowBanner:$false
Invoke-WebRequest `
-Uri "https://raw.githubusercontent.com/JustinIven/smtp-oauth-relay/main/New-RelayEntraApp.ps1" `
-OutFile "New-RelayEntraApp.ps1"
.\New-RelayEntraApp.ps1 -DisplayName "SMTP OAuth Relay" -SenderAddress "noreply@example.com"
The script prints the SMTP username (tenant_id@client_id) and SMTP password (client secret). Save them — the secret cannot be retrieved later.
2. Run the relay
docker run --name smtp-relay -p 8025:8025 \
-e TLS_SOURCE=off \
-e REQUIRE_TLS=false \
ghcr.io/justiniven/smtp-oauth-relay:latest
Warning
Only disable TLS for testing in a trusted network. Use TLS_SOURCE=file or TLS_SOURCE=keyvault in production.
Or deploy to Azure Container Instances:
3. Point your client at the relay
| Setting | Value |
|---|---|
| Server | Your relay hostname |
| Port | 8025 |
| Security | STARTTLS |
| Username | tenant_id@client_id (from step 1) |
| Password | Client secret (from step 1) |
Verify with PowerShell:
$cred = Get-Credential # User: tenant_id@client_id Password: client_secret
Send-MailMessage -SmtpServer relay.example.com -Port 8025 `
-Credential $cred `
-From noreply@example.com -To you@example.com `
-Subject 'Relay test' -Body 'Relay test'
Or with swaks:
swaks --server relay.example.com:8025 \
--auth-user 'tenant_id@client_id' --auth-password 'client_secret' \
--from noreply@example.com --to you@example.com --body 'Relay test'
Documentation
- Installation — Docker, Azure, Kubernetes, manual
- Entra ID setup — app registration and sender restrictions
- Configuration — environment variable reference
- Client setup — printers, NAS, firewalls, apps
- Authentication — username formats and encoding
- Azure Tables — central credential lookup
- Architecture · FAQ
Known limitations
- The Microsoft Graph
user: sendMailendpoint always sends from the primary mailbox; alias addresses are not honored (#80).
Support
- Bugs and feature requests: GitHub Issues
- Pull requests welcome.
License
Apache License 2.0 — see LICENSE.
Built with aiosmtpd, the Microsoft Graph API, and the Microsoft Identity Platform.