SMTP to Microsoft Graph
How to Install and Configure SMTP2Graph on Linux
Replace SMTP AUTH with Microsoft Graph API — no user license required.
Table of Contents
- Introduction
- Prerequisites
- Register an Application in Entra ID
- Install the SMTP2Graph Binary
- Create the Configuration File
- Create the systemd Service
- Set Permissions
- Enable and Start the Service
- Test the Relay
- Troubleshooting
Introduction
Microsoft is retiring Basic Authentication for SMTP AUTH in Exchange Online. If you have devices, applications, or scripts that need to send email through Microsoft 365, you need to migrate to a modern approach.
SMTP2Graph is a lightweight, open-source SMTP server that accepts mail locally and relays it to Exchange Online via the Microsoft Graph API. It runs as a single binary on Linux, macOS, or Windows, and doesn’t require a user license — only an Entra ID (Azure AD) app registration with the Mail.Send permission.
Key features include SMTP AUTH support (PLAIN/LOGIN), TLS, IP whitelisting, FROM whitelisting, rate limiting, brute force protection, and zero SPF/DKIM/DMARC headaches since Microsoft 365 handles all of that.
Prerequisites
- A Linux server (Debian, Ubuntu, RHEL, etc.)
- A Microsoft 365 / Exchange Online tenant
- Admin access to the Entra ID (Azure AD) portal
- A mailbox to send as (can be a shared mailbox — no license needed)
Step 1 — Register an Application in Entra ID
Go to entra.microsoft.com → App registrations → New registration. Name it something descriptive like SMTP2Graph Relay. Leave the redirect URI empty. Click Register.
Note the Application (client) ID and Directory (tenant) ID from the Overview page.
Go to Certificates & secrets → New client secret. Copy the Value immediately — you won’t be able to see it again.
Go to API permissions → Add a permission → Microsoft Graph → Application permissions → search for Mail.Send → Add.
Click Grant admin consent for your tenant. Confirm that the status column shows a green checkmark.
Security note: The
Mail.Sendapplication permission allows sending as any mailbox in your tenant by default. To restrict this, configure an Application Access Policy in Exchange Online to scope the app to specific mailboxes.
Step 2 — Install the SMTP2Graph Binary
Download the latest release from GitHub and place it in the standard location for user-installed binaries:
# Download the latest release (adjust URL for your architecture)
wget https://github.com/SMTP2Graph/SMTP2Graph/releases/latest/download/smtp2graph-linux-x64 \
-O /tmp/smtp2graph
# Install the binary
sudo cp /tmp/smtp2graph /usr/local/bin/smtp2graph
sudo chmod +x /usr/local/bin/smtp2graph
/usr/local/bin/ is the canonical FHS (Filesystem Hierarchy Standard) path for locally installed binaries not managed by the system package manager. ARM builds are also available on the releases page.
Step 3 — Create the Configuration File
sudo mkdir -p /etc/smtp2graph
sudo nano /etc/smtp2graph/config.yml
Paste the following and fill in your Entra ID values:
mode: full
send:
appReg:
tenant: YOUR_TENANT_ID
id: YOUR_CLIENT_ID
secret: YOUR_CLIENT_SECRET
receive:
port: 25
requireAuth: true
allowInsecureAuth: false
users:
- username: relay
password: YourStrongPassword!
Set requireAuth: true and allowInsecureAuth: false to enforce authenticated and encrypted connections. If your sending devices don’t support TLS, you may need to set allowInsecureAuth: true, but limit access by IP instead.
Step 4 — Create the systemd Service
Create a dedicated service account and data directory:
sudo useradd -r -s /usr/sbin/nologin -d /var/lib/smtp2graph smtp2graph
sudo mkdir -p /var/lib/smtp2graph
sudo chown smtp2graph:smtp2graph /var/lib/smtp2graph
SMTP2Graph reads config.yml from its working directory. We use a symlink so the config lives cleanly in /etc/ while the binary finds it where it expects.
Create the unit file:
sudo nano /etc/systemd/system/smtp2graph.service
[Unit]
Description=SMTP2Graph - SMTP to Microsoft Graph relay
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=smtp2graph
Group=smtp2graph
ExecStartPre=/bin/ln -sf /etc/smtp2graph/config.yml /var/lib/smtp2graph/config.yml
ExecStart=/usr/local/bin/smtp2graph
WorkingDirectory=/var/lib/smtp2graph
Restart=on-failure
RestartSec=5
# Required if listening on port 25 (below 1024)
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
# Hardening
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadOnlyPaths=/etc/smtp2graph
ReadWritePaths=/var/lib/smtp2graph
PrivateTmp=yes
[Install]
WantedBy=multi-user.target
The ExecStartPre line creates a symlink so that config.yml is available in the working directory. The AmbientCapabilities lines allow the non-root service user to bind to port 25. If you use port 587 or higher, you can remove those two lines.
Step 5 — Set Permissions
Protect the configuration file since it contains your Entra ID client secret:
sudo chown root:smtp2graph /etc/smtp2graph/config.yml
sudo chmod 640 /etc/smtp2graph/config.yml
sudo chown -R smtp2graph:smtp2graph /var/lib/smtp2graph
This ensures only root and the smtp2graph service account can read the config.
Step 6 — Enable and Start the Service
sudo systemctl daemon-reload
sudo systemctl enable --now smtp2graph
Check the status:
sudo systemctl status smtp2graph
journalctl -u smtp2graph -f
You should see the SMTP server start and listen on the configured port. Logs are also written to /var/lib/smtp2graph/logs/.
Step 7 — Test the Relay
Send a test email using swaks (Swiss Army Knife for SMTP):
# Install swaks if needed
sudo apt install swaks # Debian/Ubuntu
sudo dnf install swaks # RHEL/Fedora
# Send a test message
swaks \
--to recipient@example.com \
--from sender@yourdomain.com \
--server 127.0.0.1 \
--port 25 \
--auth LOGIN \
--auth-user relay \
--auth-password 'YourStrongPassword!' \
--header "Subject: SMTP2Graph Test" \
--body "Hello from SMTP2Graph!"
If everything is configured correctly, the message will be relayed through the Microsoft Graph API and delivered to the recipient.
Troubleshooting
Config not found
SMTP2Graph reads config.yml from its current working directory. Make sure the symlink is in place:
ls -la /var/lib/smtp2graph/config.yml
# Should show: config.yml -> /etc/smtp2graph/config.yml
Permission denied on port 25
Ensure the AmbientCapabilities=CAP_NET_BIND_SERVICE line is present in the service file. Alternatively, use a port above 1024 (e.g., 587) in your config.yml.
401 / 403 from Graph API
Double-check your Entra ID app registration:
- Verify
tenant,id, andsecretinconfig.yml - Confirm Mail.Send is an Application permission (not Delegated)
- Confirm Admin consent has been granted
- If using an Application Access Policy, ensure the sender mailbox is in scope
400 — Sender not allowed
The From: address must correspond to a valid mailbox in your tenant. If you’ve configured an Application Access Policy, the app must be allowed to send as that specific mailbox.
Queued messages not sending
Check the detailed logs:
cat /var/lib/smtp2graph/logs/*.log
Failed messages are stored as .eml files in the queue. Restarting the service retriggers delivery attempts.
Check what the binary is doing
# See which files the process tries to open
strace -e openat -p $(pgrep smtp2graph) 2>&1 | head -50
That’s it — you now have a production-ready SMTP relay that sends via Microsoft Graph API without needing SMTP AUTH against Exchange Online. Your devices and applications can continue sending to a standard SMTP endpoint while authentication happens securely through the Graph API with OAuth2 client credentials.
For more details, check the SMTP2Graph GitHub repository and the official documentation.