Back to tutorials
Tutorial

MTA-STS setup guide tutorial (2026): Enforce TLS for inbound email with Nginx, DNS, and a safe rollout

MTA-STS setup guide tutorial (2026) to enforce TLS for inbound email using DNS + HTTPS policy hosting with a safe rollout plan.

By Anurag Singh
Updated on Jul 18, 2026
Category: Tutorial
Share article
MTA-STS setup guide tutorial (2026): Enforce TLS for inbound email with Nginx, DNS, and a safe rollout

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.com signals 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.yourdomain with 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: use testing first, then move to enforce.
  • 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:

  1. Week 1: mode: testing, max_age: 86400, TLS-RPT enabled.
  2. Week 2: Fix any TLS-RPT issues (expired certs, incorrect MX names, handshake failures).
  3. Week 3: Change to mode: enforce, keep max_age: 86400 for a few days.
  4. After stable: Raise max_age to 604800 (7 days) or 2419200 (28 days). Bump DNS id each 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 root path and exact URL; ensure Nginx serves text/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 MX output 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_age low 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.