The problem with STARTTLS
SMTP between mail servers starts in plain text. The receiving server advertises STARTTLS in its response to EHLO, the sender asks for it, and the connection upgrades to TLS. Almost every mail server does this today, and the email deliverability checker will show you the TLS version each of your MX hosts negotiates.
The weakness is that the whole thing is opportunistic. If the STARTTLS line is missing from the EHLO response, the sender carries on in plain text. Anyone who can sit between the two servers can strip that one line and read everything, and this has been done at ISP scale. Even with STARTTLS, most sending servers do not validate the receiver's certificate: an expired, self-signed or wrong-name certificate is accepted, because refusing would mean not delivering, and mail administrators have always chosen delivery. And the MX lookup itself is unauthenticated unless the zone is DNSSEC-signed, so an attacker who can forge a DNS answer can point the sender at their own server.
What MTA-STS adds
MTA-STS (RFC 8461) lets the receiving domain publish a policy that says: my mail servers are these hostnames, they support TLS, the certificate must be valid for the hostname, and if you cannot get that, do not deliver. A sender that supports MTA-STS fetches the policy over HTTPS, so it cannot be tampered with in transit, caches it for as long as the policy says, and applies it to every delivery attempt. Gmail, Outlook.com and most large providers enforce policies as senders. Smaller mail servers mostly do not yet, which is fine: for them nothing changes.
The two parts
1. The DNS record
A TXT record at _mta-sts.example.com:
_mta-sts.example.com. TXT "v=STSv1; id=20260916T120000;"
The id is a version marker. Senders cache your policy and only re-fetch it when the id changes, so every time you edit the policy file you must change the id. A timestamp works well. Forgetting this step is the most common reason a policy change appears to do nothing.
2. The policy file
Served over HTTPS at https://mta-sts.example.com/.well-known/mta-sts.txt, with a certificate valid for mta-sts.example.com, as text/plain:
version: STSv1 mode: testing mx: mail1.example.com mx: mail2.example.com mx: *.mail.example.net max_age: 86400
Every MX hostname you publish must appear here, exactly or via a single-label wildcard. The certificates on those MX hosts must be valid for those names: publicly trusted, not expired, hostname matching. A sender enforcing the policy will refuse to deliver to a host whose certificate does not check out, so this is the moment to fix the mail server certificate you have been ignoring. max_age is how long senders may cache the policy, in seconds; start short, grow it later.
Testing mode first, always
The mode line has three values. none publishes the policy but asks senders to do nothing with it, useful for switching off. testing asks senders to validate but still deliver on failure, and to tell you about the failures. enforce means refuse to deliver on failure. Start in testing and stay there until the reports (below) have been clean for a few weeks. A typo in an MX hostname in enforce mode stops inbound mail from every large provider at once, and you will not notice until someone phones.
TLS-RPT: finding out whether it works
MTA-STS on its own gives you no feedback. TLS-RPT (RFC 8460) is the companion record that asks senders to report TLS failures to you, daily, as JSON:
_smtp._tls.example.com. TXT "v=TLSRPTv1; rua=mailto:[email protected]"
Reports say which sender, which MX, how many sessions succeeded and which failure type was seen (certificate expired, hostname mismatch, STARTTLS not offered, policy could not be fetched). In testing mode these are what tell you whether you are ready to enforce. In enforce mode they are your alarm. Point rua at a mailbox or a service that parses them; the JSON is readable by hand but tedious after the first week.
A rollout that will not lose mail
- Fix the MX certificates. Run the SSL/TLS checker on port 25 against each MX host and get every one to a trusted, matching certificate.
- Publish TLS-RPT and confirm a report arrives within a day or two.
- Publish the policy file in
testingmode with amax_ageof a day, then the DNS record. - Check it with the email deliverability checker, which fetches and validates the policy file and flags an MX that is not covered.
- Read the TLS-RPT reports for at least two weeks. Every failure is something that will become a bounce in enforce mode.
- Switch to
enforce, change theid, and raisemax_ageto a week or two once you are confident. Longer cache means better protection but slower recovery if you need to change the policy.
Things that catch people
- Changing MX records without changing the policy. Migrating mail providers now has an extra step, and the order matters: add the new MX to the policy (new
id), wait formax_age, then change the MX records. Do it the other way round and enforcing senders will refuse the new hosts. - The policy host's own certificate.
mta-sts.example.comneeds a valid certificate too, and it is a separate hostname from your website. Wildcards cover it; a certificate listing onlyexample.comandwwwdoes not. - Redirects. The policy URL must answer directly with 200. A redirect to another host is a fetch failure.
- Hosted mail providers. Google Workspace and Microsoft 365 both document the exact
mx:lines to use. Copy them; do not guess from a single MX lookup, because their hostnames vary by region. - DANE. If your zone is DNSSEC-signed you can also publish TLSA records (DANE), which some senders prefer. The two coexist; MTA-STS is the one that works without DNSSEC.