
Most “email security” work focuses on outbound mail: SPF, DKIM, DMARC, and PTR. You still need those. But they don’t stop an attacker from forcing inbound SMTP to fall back to plaintext.
This MTA-STS setup guide tutorial shows how to publish an MTA-STS policy (plus TLS-RPT reporting). With it, other mail providers will insist on TLS when delivering to your domain. You’ll also roll it out without turning launch day into a mail outage.
This walkthrough assumes you host email on a VPS or dedicated server (Postfix + Dovecot, or cPanel/WHM). You’ll add a DNS TXT record, serve a small policy file over HTTPS, and validate everything end to end.
If you want a cleaner operational baseline (static IP, stable reverse connectivity, predictable firewall rules), start on a HostMyCode VPS. Or move up to managed VPS hosting if you’d rather hand off OS maintenance.
What you’ll build (and why MTA-STS helps)
MTA-STS (Mail Transfer Agent Strict Transport Security) tells sending mail servers: “When you deliver to example.com, require TLS and only accept mail for these MX hosts.” Without it, many MTAs will still fall back to plaintext SMTP if TLS negotiation fails. A downgrade can also happen if someone interferes with TLS.
- MTA-STS policy is hosted at:
https://mta-sts.example.com/.well-known/mta-sts.txt - DNS TXT record at:
_mta-sts.example.comsignals the policy version. - TLS-RPT (optional but strongly recommended) lets senders report TLS issues to you.
MTA-STS doesn’t replace SPF/DKIM/DMARC. It complements them.
If you still need to set those up—or you want to sanity-check records and PTR alignment—use our email authentication setup guide.
Prerequisites checklist
- A domain you control (DNS access).
- Working MX records for the domain.
- HTTPS access for
mta-sts.yourdomainwith a valid certificate. - Ability to publish a TXT record (and ideally a reporting TXT record).
Important: MTA-STS depends on HTTPS availability. If your certificate breaks or renewals fail, the policy can become unreachable. When that happens, strict senders may refuse delivery.
If renewal has bitten you before, keep this nearby: TLS certificate renewal troubleshooting.
Step 1: Confirm your MX hosts and TLS actually work
Before you publish anything “strict,” confirm the basics. From any Linux machine (or your VPS), check your MX records:
dig +short MX example.com
Next, test SMTP STARTTLS against each MX host. Replace mail.example.com with your real MX hostname:
openssl s_client -starttls smtp -connect mail.example.com:25 -servername mail.example.com -showcerts
What you want to see:
- A successful TLS handshake (no immediate disconnect).
- A certificate that matches the hostname (or at least a chain that validates).
- No obvious expiry problems.
If the handshake fails, fix TLS first. On cPanel servers, you may also want: SMTP TLS troubleshooting tutorial.
Step 2: Create the MTA-STS policy file (start in “testing” mode)
The policy file is plain text with a strict format. Start with mode: testing. This tells senders to validate and report issues. It should not hard-fail delivery yet.
Create a working directory on the web server that will host the policy. On Ubuntu/Debian with Nginx, this is a clean layout:
sudo mkdir -p /var/www/mta-sts/.well-known
sudo nano /var/www/mta-sts/.well-known/mta-sts.txt
Example policy (edit to match your domain and MX hosts):
version: STSv1
mode: testing
mx: mail.example.com
mx: mx2.example.com
max_age: 86400
mode: usetestingfirst, then move toenforce.mx: list every valid MX hostname. Wildcards aren’t allowed.max_age: start with 1 day (86400). Once stable, increase to 1–4 weeks.
Pitfall: If your MX records point to a hostname you forgot to list here, strict senders can refuse delivery once you enforce.
Before moving on, reconcile your dig MX output with the policy.
Step 3: Serve the policy over HTTPS on mta-sts.yourdomain
You must host the file at exactly:
https://mta-sts.example.com/.well-known/mta-sts.txt
This section uses Nginx because it’s common on VPS builds. It’s also easy to keep separate from your main site config.
Create an Nginx server block
On Ubuntu/Debian:
sudo nano /etc/nginx/sites-available/mta-sts.example.com
Use this minimal config (adjust server_name and paths):
server {
listen 80;
server_name mta-sts.example.com;
location /.well-known/mta-sts.txt {
root /var/www/mta-sts;
default_type text/plain;
}
}
Enable it and test:
sudo ln -s /etc/nginx/sites-available/mta-sts.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Issue a TLS certificate
If you already run Certbot, the simplest approach is an HTTP challenge on port 80. On Ubuntu:
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d mta-sts.example.com
After issuance, force HTTPS and keep the content-type consistent:
sudo nano /etc/nginx/sites-available/mta-sts.example.com
server {
listen 80;
server_name mta-sts.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name mta-sts.example.com;
ssl_certificate /etc/letsencrypt/live/mta-sts.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mta-sts.example.com/privkey.pem;
location = /.well-known/mta-sts.txt {
root /var/www/mta-sts;
default_type text/plain;
add_header Cache-Control "max-age=300";
}
}
Reload again:
sudo nginx -t
sudo systemctl reload nginx
Validate the URL from your terminal:
curl -i https://mta-sts.example.com/.well-known/mta-sts.txt
You should get 200 OK and see your policy content. A 404 usually means your root path is wrong. Certificate warnings mean you should stop and fix TLS before publishing DNS.
Step 4: Publish the _mta-sts DNS TXT record (with versioning)
Next, add the TXT record that tells senders which policy “version” to use. In your DNS zone, create:
- Type: TXT
- Name/Host:
_mta-sts - Value:
v=STSv1; id=2026071801 - TTL: 300–3600 while testing
The id can be any string, but treat it like a version number. When you make a meaningful policy change, bump the ID.
Receivers cache aggressively. The ID is what nudges them to re-fetch.
If you manage DNS for client domains or multiple properties, your registrar + DNS workflow matters. HostMyCode keeps the basics straightforward for small teams: domains and DNS at HostMyCode.
Verify the TXT record:
dig +short TXT _mta-sts.example.com
Step 5: Add TLS-RPT reporting so you can see breakage early
MTA-STS is safer when you can see what other providers see. TLS-RPT lets major senders send aggregate reports when TLS fails, policies don’t match, or certificates break.
Publish this DNS record:
- Type: TXT
- Name/Host:
_smtp._tls - Value:
v=TLSRPTv1; rua=mailto:tlsrpt@example.com
Use a mailbox you actually monitor. On cPanel, a dedicated address plus filters is usually enough.
If you’re already fighting outbound reputation issues, clean that up first. Reports won’t help if your reporting inbox is unusable. Reference: cPanel outbound spam cleanup.
Step 6: Validate end-to-end (policy fetch + syntax + TLS)
You can cover the core requirements with a few direct checks.
Check that policy is reachable and unmodified
curl -sS https://mta-sts.example.com/.well-known/mta-sts.txt
Make sure:
- No HTML wrappers.
- No redirects other than HTTP→HTTPS.
- File is exactly the format you expect.
Confirm certificate chain and SNI
openssl s_client -connect mta-sts.example.com:443 -servername mta-sts.example.com </dev/null
Re-check MX inventory against the policy
If your MX records are managed elsewhere, confirm they didn’t drift. This is a common “silent break” after migrations.
dig +short MX example.com
If you’re planning a mail server move, do that first. Then publish your policy.
For web-side cutover mechanics (TTL planning, rollback), this is a solid reference: web hosting migration with a staging cutover.
Step 7: Move from “testing” to “enforce” (safe rollout plan)
Use a rollout that gives you time to catch mistakes before they cost you mail:
- Week 1:
mode: testing,max_age: 86400, TLS-RPT enabled. - Week 2: Fix any TLS-RPT issues (expired certs, incorrect MX names, handshake failures).
- Week 3: Change to
mode: enforce, keepmax_age: 86400for a few days. - After stable: Raise
max_ageto 604800 (7 days) or 2419200 (28 days). Bump DNSideach change.
To switch modes, edit the policy file and bump the DNS ID:
sudo nano /var/www/mta-sts/.well-known/mta-sts.txt
version: STSv1
mode: enforce
mx: mail.example.com
mx: mx2.example.com
max_age: 604800
Then update:
_mta-sts.example.com TXT v=STSv1; id=2026071802
Common failure modes (and quick fixes)
Most MTA-STS problems come from small, fixable mistakes. Focus your checks on the few parts that actually affect receivers.
1) Policy returns 404 or HTML
- Symptom: senders can’t fetch policy; TLS-RPT reports “policy fetch failed.”
- Fix: verify
rootpath and exact URL; ensure Nginx servestext/plain.
2) Certificate renewal broke the endpoint
- Symptom: policy fetch fails after renewal; cert chain mismatch.
- Fix: run
sudo certbot renew --dry-run; check ACME challenges. Use our renewal troubleshooting guide if needed.
3) MX names don’t match policy
- Symptom: TLS works, but sender says “MX mismatch.”
- Fix: policy must list the MX hostnames, not IPs. Confirm
dig MXoutput and match exactly.
4) Firewall blocks inbound port 25 from parts of the internet
- Symptom: intermittent delivery problems; certain senders time out.
- Fix: verify your VPS security groups and host firewall. If you’re troubleshooting rules, keep this handy: firewall troubleshooting on a hosting VPS.
Operational checklist for resellers and multi-domain hosting
- Standardize a small Nginx vhost template for
mta-sts.<domain>. - Use one mailbox pattern for TLS-RPT (for example,
tlsrpt@<domain>). - Keep
max_agelow until you’ve seen a full renewal cycle for the MTA-STS certificate. - Document which MX hosts each domain uses; don’t “guess from memory.”
- After any mail migration, re-validate MTA-STS fetch, TXT records, and STARTTLS on port 25.
Summary: enforce TLS for inbound email without surprising yourself
MTA-STS is one of the few controls that directly reduces downgrade risk for inbound delivery. Stage it carefully. Start in testing, keep max_age short, and read your TLS-RPT reports.
You’ll usually catch issues long before users notice missing mail.
If you want a steady platform for mail and DNS security work, run it on a HostMyCode VPS. Or choose managed VPS hosting if you’d rather delegate patching, monitoring, and baseline hardening. HostMyCode keeps the promise simple: Affordable & Reliable Hosting.
If you’re rolling out MTA-STS across production domains, start from infrastructure you can depend on: stable networking, clean DNS control, and SSL renewals that don’t surprise you. HostMyCode offers VPS hosting for hands-on admins and managed VPS plans when you want less operational overhead.
FAQ
Should I publish MTA-STS if I use Google Workspace or Microsoft 365?
Yes, if you control DNS. Your policy should list the MX hostnames your provider publishes for your domain. Start in testing mode and enable TLS-RPT so you can catch mismatches early.
Do I need a dedicated server just to host the MTA-STS policy file?
No. The file is tiny. You can host it on the same VPS as your website, on a separate lightweight VPS, or behind a CDN—as long as it’s reachable via HTTPS at mta-sts.yourdomain.
How often should I change the MTA-STS “id” in DNS?
Change it whenever you change the policy content (mode, max_age, or MX list). Treat it like a version number so receivers know to re-fetch.
Can MTA-STS break inbound email?
It can if you publish mode: enforce while your MX hosts can’t negotiate TLS reliably, your certificate is invalid, or your MX list doesn’t match reality. That’s why the safe path is testing + TLS-RPT first.
Is MTA-STS the same as DANE?
No. DANE relies on DNSSEC and TLSA records to authenticate certificates. MTA-STS relies on HTTPS + a DNS TXT pointer. Some organizations run both; many start with MTA-STS because it’s simpler operationally.