Creating an SMTP Relay with Azure Email Communication Services
Overview
You will build an SMTP relay on Azure: a mail server address that your apps, scripts,
printers and Linux servers can send through, with no mail server to maintain.
It takes three Azure pieces working together:
- Email Communication Service: holds your sending domain (and its DNS/authentication)
- Communication Service: the resource that actually sends, and owns the SMTP credentials
- Microsoft Entra app registration: the identity behind your SMTP username and password
The finished relay settings look like this:
Server smtp.azurecomm.net
Port 587 (STARTTLS required)
Username <Communication Services name>.<App client ID>.<Tenant ID>
Password The app registration's client secret
Prerequisites
- An Azure subscription (a free account works, but see the cost note below)
- Permission to create resources, and to create app registrations in Microsoft Entra ID
- If you want to send from your own domain: access to its DNS records
- A terminal for testing (Linux, macOS, or Windows PowerShell)
Costs and limits (check this first)
- Azure Communication Services Email is pay-as-you-go: a tiny charge per email plus a small charge per MB of data. It is not part of the always-free VM allowance. Check the current price on the Azure pricing page and set a budget alert.
- New resources start with low sending limits (on the order of tens of emails per minute and a few hundred per hour). The free Azure-managed domain has even stricter limits. You can request a higher quota from the Azure portal.
- Email Communication Service is for legitimate transactional and low-volume mail. Bulk marketing or unsolicited mail will get your resource suspended.
- Screens and wording change often. If a button is not where this guide says, use the portal search bar and the resource menu on the left.
Step 1: Create a Resource Group
1. Sign in at portal.azure.com
2. Search for "Resource groups" → Create
3. Subscription: your subscription
4. Resource group: smtp-relay-rg
5. Region: a region near you
6. Review + create → Create
Step 2: Create the Email Communication Service
1. In the search bar, type "Email Communication Services" and open it
2. Click Create
3. Subscription and resource group: smtp-relay-rg
4. Name: smtp-relay-email
5. Data location: the country/region where email data is stored (this cannot be changed later, and it must match the Communication Service you create in Step 4)
6. Review + create → Create → Go to resource
Step 3: Add a Sending Domain
You have two choices. The Azure-managed domain is instant and good for testing. A custom domain is required for real use, because your mail will pass SPF and DKIM as your own domain.
Option A: Azure-managed domain (fast, for testing)
1. In smtp-relay-email, open Provision domains
2. Click Add domain → Azure subdomain
3. Wait for the status to show Verified
4. Your sender address is DoNotReply@<random-guid>.azurecomm.net (shown on the domain page)
Option B: Custom domain (recommended for real mail)
1. Provision domains → Add domain → Custom domain
2. Enter your domain (for example mail.example.com or example.com) and confirm
3. Click the domain, then Verify domain
4. Add the DNS records that the portal shows you at your DNS provider:
- Domain verification: a TXT record
- SPF: a TXT record (if you already have an SPF record, merge the include into it; never publish two SPF records)
- DKIM: two CNAME records (selector1 and selector2)
5. Wait for DNS to propagate (minutes to a few hours), then click Verify next to each record until all show Verified
6. Add a DMARC record for your domain too, for example:
_dmarc.example.com TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com"
Add the sender addresses (MailFrom) for a custom domain:
1. Open the domain → MailFrom addresses → Add
2. Enter a display name and a username (for example noreply, alerts)
3. Your senders become noreply@example.com, alerts@example.com, and so on
Remember: the From address your relay clients use must be one of these.
Step 4: Create the Communication Service
1. In the search bar, type "Communication Services" and open it
2. Click Create
3. Subscription and resource group: smtp-relay-rg
4. Name: smtp-relay-acs (note this name; it is part of the SMTP username)
5. Data location: the same as Step 2
6. Review + create → Create → Go to resource
Step 5: Connect the Domain to the Communication Service
1. In smtp-relay-acs, go to Email → Domains
2. Click Connect domain
3. Pick your subscription, resource group, the Email Communication Service (smtp-relay-email) and the verified domain
4. Click Connect
The domain now appears in the list. Until this is done, sending fails with a sender or domain error.
Step 6: Create the App Registration (the SMTP identity)
1. In the search bar, open Microsoft Entra ID
2. App registrations → New registration
3. Name: smtp-relay-app
4. Supported account types: Single tenant
5. Click Register
6. On the Overview page copy and save:
- Application (client) ID
- Directory (tenant) ID
7. Certificates & secrets → Client secrets → New client secret
8. Give it a description and an expiry (for example 12 or 24 months) → Add
9. Copy the secret Value right now. It is shown only once. This is your SMTP password
Step 7: Give the App Permission to Send
1. Back in smtp-relay-acs, open Access control (IAM)
2. Add → Add role assignment
3. Role: Communication and Email Service Owner (a custom role; search for it by name)
4. Members → Select members → search for smtp-relay-app → Select
5. Review + assign
Without this role, the login works but sending is refused.
Step 8: Create the SMTP Username
1. In smtp-relay-acs, open Settings → SMTP Usernames
2. Click Add SMTP Username
3. Select the app registration (smtp-relay-app)
4. Choose the username. The default format is:
smtp-relay-acs.<Application-client-ID>.<Directory-tenant-ID>
(Some portal versions also let you set a shorter custom username, such as your sender's email address.)
5. Save, and copy the username
Your relay is now ready:
Host smtp.azurecomm.net
Port 587 (STARTTLS)
Username smtp-relay-acs.<client-ID>.<tenant-ID>
Password <client secret value>
From any MailFrom address you set up in Step 3
Step 9: Test It
Using swaks (install with sudo apt install swaks):
swaks --server smtp.azurecomm.net --port 587 --tls \
--auth LOGIN --auth-user 'smtp-relay-acs.CLIENT_ID.TENANT_ID' --auth-password 'YOUR_SECRET' \
--from 'DoNotReply@your-domain.azurecomm.net' --to you@example.com \
--header 'Subject: Azure SMTP relay test' --body 'It works!'
Using Python (standard library):
import smtplib
from email.message import EmailMessage
msg = EmailMessage()
msg["From"] = "noreply@example.com"
msg["To"] = "you@example.com"
msg["Subject"] = "Azure SMTP relay test"
msg.set_content("It works!")
with smtplib.SMTP("smtp.azurecomm.net", 587) as s:
s.starttls()
s.login("smtp-relay-acs.CLIENT_ID.TENANT_ID", "YOUR_SECRET")
s.send_message(msg)
Check that the message arrived (look in Junk too). Then see the Email logs section below.
Use It as a Linux Server Relay (Postfix)
1. Install: sudo apt install postfix libsasl2-modules
2. Add to /etc/postfix/main.cf:
relayhost = [smtp.azurecomm.net]:587
smtp_use_tls = yes
smtp_tls_security_level = encrypt
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_tls_security_options = noanonymous
sender_canonical_maps = static:noreply@example.com
3. Create /etc/postfix/sasl_passwd with one line:
[smtp.azurecomm.net]:587 smtp-relay-acs.CLIENT_ID.TENANT_ID:YOUR_SECRET
4. Lock it down and load it:
sudo chmod 600 /etc/postfix/sasl_passwd
sudo postmap /etc/postfix/sasl_passwd
sudo systemctl restart postfix
5. Test:
echo "Relay test" | mail -s "Postfix via Azure" you@example.com
The sender_canonical_maps line rewrites every From address to a verified sender.
Azure rejects mail whose From is not a configured MailFrom address (for example root@server.local).
Other Clients
Applications, printers, scanners and CMS plugins use the same four settings: host smtp.azurecomm.net, port 587, STARTTLS/TLS on, and the username and secret from above. Authentication type is LOGIN (or PLAIN). Anything that can only use port 25 without authentication will not work.
Check What Was Sent
1. Add diagnostics: smtp-relay-acs → Monitoring → Diagnostic settings → Add → send Email logs (send, status, and engagement) to a Log Analytics workspace
2. Open Logs and query the email tables to see delivered, bounced, and suppressed messages
3. The Communication Service's Overview and Insights pages also show send counts
Troubleshooting
535 authentication failed Wrong username format or secret, an expired secret, or a typo. Regenerate the secret if in doubt
Auth works but send is refused The app lacks the Communication and Email Service Owner role (Step 7)
Sender / domain not allowed The domain is not connected (Step 5) or the From address is not a MailFrom address
Message rejected as unauthenticated DNS records (SPF/DKIM) are not verified yet or are wrong
Throttled (429 or 4xx) You hit the sending limit. Slow down or request a higher quota
Mail lands in spam Use a custom domain with SPF, DKIM and DMARC, avoid spammy content, warm up slowly
Cannot connect Outbound port 587 is blocked by your network or ISP. Try another network
Secret stopped working Client secrets expire. Create a new one and update every client
Cleanup When Done
1. Communication Services → Settings → SMTP Usernames → remove the username
2. Microsoft Entra ID → App registrations → smtp-relay-app → delete (this also removes the secret)
3. Resource groups → smtp-relay-rg → Delete resource group → type the name to confirm
4. Remove the DNS records you added for the custom domain
Quick Reference
Resources Email Communication Service + Communication Service + Entra app registration
Domain Azure-managed (test) or custom (SPF, DKIM, DMARC) - must be Verified and connected
Role Communication and Email Service Owner on the Communication Service
Server smtp.azurecomm.net : 587 (STARTTLS)
Username <ACS name>.<client ID>.<tenant ID>
Password Client secret value
Tips
Use a custom domain with SPF, DKIM and DMARC for anything real. The Azure-managed domain is for testing and has tighter limits.
Store the client secret in a password manager or secrets store, never in code or a git repo.
Client secrets expire. Put the expiry date in your calendar, or create a second secret before the first one runs out.
Use one app registration (and SMTP username) per application so you can revoke one without breaking the others.
Send only from addresses you added as MailFrom addresses, and keep the volume within your quota.
Set a budget alert on the resource group so a runaway script cannot run up a bill.
Azure changes screens and limits often. Confirm the details in the Azure Communication Services email documentation before relying on any number in this guide.