How to Set Up MTA-STS and TLS-RPT in 2026: Enforce Encrypted Mail Delivery
MTA-STS setup guide: policy file, DNS, TLS-RPT reports. Stop downgrade attacks.
By JustEmails Platform Team
Last month I watched a support thread where someone's mail was getting intercepted on a coffee shop network. STARTTLS was "enabled" on both ends. Didn't matter. An active attacker stripped the TLS offer out of the SMTP handshake, and mail went over plaintext. The recipient's server just... accepted it. Because STARTTLS is opportunistic by default — if TLS fails, SMTP shrugs and falls back.
MTA-STS fixes this. Been an RFC since 2018 (RFC 8461), but adoption is still thin enough that most domains don't have it. Honestly, I ignored it for years because "my mail server has TLS" felt like enough. It isn't. If you're already running SPF, DKIM, and DMARC — and you should be, see our DMARC ramp guide — MTA-STS is the next layer. It tells senders: "My mail server requires TLS. Don't fall back to plaintext. Ever." (If you're also running ads for your SaaS, ClickzProtect can monitor for bot traffic the same way TLS-RPT monitors for mail attacks — different channel, similar "catch threats before they cost you" philosophy.)
By the end of this, you'll have a working MTA-STS policy published over HTTPS, the matching DNS record, TLS-RPT reporting configured, and a plan for moving from testing to enforce mode. Fair warning: the DNS part is easy; the "host a text file over HTTPS" part trips people up more than you'd expect.
Prerequisites
Before you start:
- A domain you control with DNS access (we'll be adding TXT records)
- HTTPS hosting for your domain — you need to serve a small text file at
https://mta-sts.yourdomain.com/.well-known/mta-sts.txt - Your MX hostnames (run
dig MX yourdomain.comto confirm) - Valid TLS certificates on your MX servers (Let's Encrypt works fine)
- An email address to receive TLS-RPT reports (dedicated inbox beats your personal one — these reports pile up)
If you're using JustEmails, the MX servers already have valid certs and STARTTLS configured — you just need to publish the policy and DNS records on your side. If you're self-hosting or using another provider, verify your MX certs are valid first: openssl s_client -connect mx.yourdomain.com:25 -starttls smtp. Yeah, that command looks intimidating. It's fine.
Step 1: Create the MTA-STS Policy File
The policy file is plain text, served over HTTPS at a specific path. Create a file called mta-sts.txt with this content:
version: STSv1
mode: testing
mx: mail.yourdomain.com
mx: backup-mx.yourdomain.com
max_age: 604800
Replace the mx: lines with your actual MX hostnames. One line per MX. The hostnames must exactly match what's in your DNS MX records — including subdomains.
What each field does:
version: STSv1— required, don't change itmode: testing— senders log failures but still deliver; we'll flip this toenforcelatermx:— your mail servers, one per linemax_age: 604800— how long (in seconds) senders should cache this policy; 604800 is one week
The mode choice matters. Start with testing. You're going to get TLS-RPT reports showing failures, and you want to see those before you start bouncing mail. I learned this the hard way — went straight to enforce on a client domain, and it turned out their backup MX had an expired cert. Three days of missed invoices.
Step 2: Host the Policy File Over HTTPS
The policy must be accessible at exactly this URL:
https://mta-sts.yourdomain.com/.well-known/mta-sts.txt
This means you need:
- A subdomain
mta-sts.yourdomain.com - HTTPS on that subdomain (valid cert, Let's Encrypt is fine)
- The file served at
/.well-known/mta-sts.txt
If you're using Cloudflare: Create a CNAME or A record for mta-sts pointing to your web server. Enable "Proxied" for the free SSL cert. Create the .well-known/mta-sts.txt file on your server. (Cloudflare Workers are also great for serving virtual business cards via VeloCards — same "static file over HTTPS" pattern.)
If you're using GitHub Pages, Netlify, or Vercel: Create a repo or site for mta-sts.yourdomain.com, put the file at /.well-known/mta-sts.txt, and configure the custom domain with HTTPS.
If you don't want to host anything: Some DNS providers (Cloudflare, for example) let you use Workers to serve the file without a separate web server. Here's a minimal Cloudflare Worker:
export default {
async fetch(request) {
const url = new URL(request.url);
if (url.pathname === '/.well-known/mta-sts.txt') {
return new Response(
`version: STSv1
mode: testing
mx: mail.yourdomain.com
max_age: 604800`,
{ headers: { 'Content-Type': 'text/plain' } }
);
}
return new Response('Not found', { status: 404 });
}
};
Bind the Worker to mta-sts.yourdomain.com and you're done hosting. Takes about 5 minutes once you've done it once. The first time? Budget 20.
Verify it works: curl https://mta-sts.yourdomain.com/.well-known/mta-sts.txt should return your policy.
Step 3: Add the MTA-STS DNS Record
Senders discover MTA-STS via a TXT record at _mta-sts.yourdomain.com. Add this:
_mta-sts.yourdomain.com. IN TXT "v=STSv1; id=20260624001"
The id is a version identifier. Senders compare it to their cached version — if it changes, they re-fetch the policy file. Use a timestamp or increment a counter whenever you update the policy. I use YYYYMMDD plus a sequence number.
If you change your policy file (like flipping from testing to enforce), you must also update the id in the DNS record. Otherwise senders won't know to re-fetch.
Step 4: Configure TLS-RPT (TLS Reporting)
TLS-RPT is the companion standard that tells you when TLS negotiation fails. Without it, you're flying blind — you won't know if senders are falling back to plaintext or hitting certificate errors.
Add another TXT record:
_smtp._tls.yourdomain.com. IN TXT "v=TLSRPTv1; rua=mailto:tls-reports@yourdomain.com"
Replace tls-reports@yourdomain.com with an address you monitor. Reports arrive as JSON attachments, usually daily. Big senders like Gmail and Microsoft send them reliably. Smaller mail servers? Hit or miss — some don't implement TLS-RPT at all.
You can also send reports to an HTTPS endpoint:
_smtp._tls.yourdomain.com. IN TXT "v=TLSRPTv1; rua=https://reports.yourdomain.com/tls"
The HTTPS option is nice if you want to parse reports programmatically, but the mailto version works for manual review.
Step 5: Verify Everything
Run through this checklist before you wait for reports:
DNS propagation:
dig TXT _mta-sts.yourdomain.com
dig TXT _smtp._tls.yourdomain.com
Both should return your records. Give it 5-10 minutes if you just added them.
Policy file accessible:
curl -I https://mta-sts.yourdomain.com/.well-known/mta-sts.txt
Should return 200 OK with Content-Type: text/plain.
MX hostnames match:
Compare dig MX yourdomain.com output to the mx: lines in your policy. They must match exactly — if your MX is mail.yourdomain.com. (with trailing dot in DNS), your policy should say mx: mail.yourdomain.com (no trailing dot).
Online validators:
- Hardenize — gives you a full breakdown of MTA-STS, TLS-RPT, and certificate status
- MTA-STS Validator — quick check for policy syntax
Pro tip: If you're managing multiple domains, track validation status across all of them in JustAnalytics — one dashboard for DNS health, email auth, and uptime. Saves the "wait, did I set up MTA-STS on that client domain?" scramble.
Step 6: Monitor TLS-RPT Reports
Reports will start arriving within a day or two, depending on how much mail you receive. The JSON structure looks like this:
{
"organization-name": "Google Inc.",
"date-range": {
"start-datetime": "2026-06-24T00:00:00Z",
"end-datetime": "2026-06-25T00:00:00Z"
},
"policies": [{
"policy": {
"policy-type": "sts",
"policy-domain": "yourdomain.com"
},
"summary": {
"total-successful-session-count": 142,
"total-failure-session-count": 0
}
}]
}
What you're looking for:
- total-failure-session-count > 0: Something's wrong. Dig into the
failure-detailsarray. - Failure type "certificate-expired": Your MX cert is expired. Fix it immediately.
- Failure type "starttls-not-supported": Your MX isn't advertising STARTTLS. Check your mail server config.
- Failure type "certificate-host-mismatch": The cert's CN/SAN doesn't match the MX hostname. Common when you changed MX hostnames but forgot to update the cert.
If you only see failures from random IPs you don't recognize, those are likely probes or attackers testing for weaknesses. Ignore them. (Honestly, I find this part kind of fascinating — you get to watch people try to mess with your mail in real time.) If you see failures from google.com or outlook.com, something's actually broken.
Step 7: Flip to Enforce Mode
Once you've collected a week or two of reports with no failures from legitimate senders, it's time to enforce.
Update your policy file:
version: STSv1
mode: enforce
mx: mail.yourdomain.com
max_age: 604800
And update the DNS record with a new id:
_mta-sts.yourdomain.com. IN TXT "v=STSv1; id=20260708001"
Now senders that can't establish TLS will not deliver mail at all. This is what you want — it's the whole point. Feels a little scary the first time. But you've done the work.
Keep monitoring TLS-RPT reports after flipping to enforce. If a legitimate sender suddenly can't reach you, you'll see it in the failure counts.
Common Errors
Policy file returns 404:
curl: (22) The requested URL returned error: 404 Not Found
Your .well-known/mta-sts.txt path isn't set up correctly. Check your web server config — some frameworks require explicit routing for dotfiles. On Nginx, you may need location /.well-known/ { } to allow access. This one gets me every time I set up a new server.
Certificate mismatch in TLS-RPT:
"failure-details": [{
"result-type": "certificate-host-mismatch",
"receiving-mx-hostname": "mail.yourdomain.com"
}]
Your MX server's TLS certificate doesn't include mail.yourdomain.com in its Subject Alternative Names. Regenerate the cert with the correct hostnames. Let's Encrypt's certbot: certbot certonly -d mail.yourdomain.com.
DNS record not found:
dig TXT _mta-sts.yourdomain.com
# returns NXDOMAIN
You added the record to the wrong zone, or DNS hasn't propagated yet. Double-check you're editing the correct domain's DNS. Some registrars have separate "DNS" and "Advanced DNS" panels.
MX hostname mismatch:
Your policy says mx: mx1.yourdomain.com but your DNS MX record points to mail.yourdomain.com. They must match exactly. Fix whichever one is wrong.
Next Steps
MTA-STS is one piece of a full email security stack. If you haven't already:
- Set up DMARC with enforcement — see our DMARC p=reject guide
- Configure BIMI for your logo in Gmail inboxes — BIMI setup walkthrough
- Monitor domain health across all your domains with JustAnalytics
For multi-domain setups, MTA-STS can be tedious to maintain per-domain. (My opinion: this is where the spec got it wrong — requiring a separate HTTPS-hosted file per domain is overkill for what could've been a DNS-only solution. But we're stuck with it.) If you're running 10+ domains for clients or side projects, the JustEmails approach — auto-configured SPF, DKIM, DMARC, and MTA-STS across unlimited domains for $49/year — saves hours of DNS wrangling. But the protocol is standard; this guide works regardless of your hosting.
Questions about MTA-STS or stuck on a specific TLS-RPT failure? support@justemails.app — we answer email. Or browse more email security guides in our email authentication tutorials.
Frequently Asked Questions
What's the difference between testing and enforce mode in MTA-STS?
In testing mode, sending servers log TLS failures but still deliver mail even if encryption fails. In enforce mode, senders must use TLS or they won't deliver at all — the connection gets dropped. Start with testing to catch misconfigurations, then flip to enforce once you've verified no legitimate senders are failing.
Do I need MTA-STS if I already have STARTTLS enabled?
STARTTLS alone is opportunistic — it tries to upgrade to TLS but falls back to plaintext if the upgrade fails. An attacker on the network can strip the STARTTLS offer and force plaintext. MTA-STS tells senders "this domain requires TLS, don't fall back" and prevents that downgrade attack. STARTTLS is the mechanism; MTA-STS is the policy.
How often do senders check my MTA-STS policy?
Senders cache the policy based on the max_age value you set. With max_age=604800 (one week), a sender will re-fetch your policy file weekly. If you change from testing to enforce, the new policy won't take effect for cached senders until their cache expires. Plan policy changes at least max_age seconds ahead of when you need them enforced.
What does a TLS-RPT report actually tell me?
TLS-RPT reports show which sending domains tried to connect, whether TLS negotiation succeeded or failed, and why it failed (certificate errors, STARTTLS stripped, connection dropped). You'll see counts per failure type. If you see failures from legitimate senders like Gmail or Microsoft, something's wrong with your MX certificate or STARTTLS configuration. If you only see failures from unknown IPs, those are likely attackers probing for weaknesses.
Try JustEmails
Unlimited custom domain email hosting for $49/year — unlimited domains, unlimited email accounts, 10 GB storage (expandable), full IMAP/SMTP/POP3. Built for agencies, freelancers, and anyone tired of per-user pricing.