MTA-STS and TLS-RPT: enforce TLS for inbound mail
Set up MTA-STS and TLS-RPT step by step: the _mta-sts and _smtp._tls records, the policy file, testing vs enforce mode, and reading TLS reports.
By Exmoor Software7 min read
Mail between servers is usually encrypted with STARTTLS, but only opportunistically. If an attacker strips the 250 STARTTLS line from your server’s response or redirects the connection, a sender using opportunistic TLS quietly falls back to plain text or accepts any certificate. Nobody sees an error. (How STARTTLS works covers the basics.)
MTA-STS (RFC 8461) lets you publish a policy that says: my MX servers support TLS with a valid certificate — don’t deliver to them any other way. TLS-RPT (RFC 8460) asks senders for a daily report on their TLS connections to you.
Both protect inbound mail, and only from senders that implement them — Google and Microsoft both document that their outbound mail honors MTA-STS. Other senders deliver as before.
How MTA-STS works
There are three parts:
- A TXT record at
_mta-sts.example.comannounces the policy and its versionid. - A policy file at
https://mta-sts.example.com/.well-known/mta-sts.txtlists your MX hosts, the mode, and how long to cache it. - Your MX servers offer STARTTLS with a publicly trusted certificate for their host name.
A sender that supports MTA-STS fetches the policy over HTTPS and caches it for max_age seconds. From then on, the MX it connects to must match an mx line in the policy, offer STARTTLS and present a valid, unexpired certificate for its name. In enforce mode, a host that fails gets no mail; the sender treats it as a temporary failure and retries.
Someone who can forge DNS answers still can’t produce a valid certificate for mta-sts.example.com. The weak point is first contact: a sender that has never fetched your policy can be tricked into thinking there is none (RFC 8461, section 10.2). That is why policies are cached for weeks.
Before you start: check your MX servers
In enforce mode, an MX without working TLS stops receiving mail from MTA-STS senders. Every host in your MX records must:
- offer STARTTLS on port 25;
- present a certificate that covers the exact MX host name (as a DNS name in the subject alternative name), chains to a public CA and has not expired — self-signed certificates and certificates for a different name fail;
- support TLS 1.2 or newer, as RFC 8461 requires of MTAs that support MTA-STS.
The SMTP and TLS test connects to each MX and shows the TLS version and certificate. Don’t skip backup MX hosts: a broken certificate there can go unnoticed until the primary fails (RFC 8461, section 8.4). Google Workspace and Microsoft 365 document MTA-STS for their MX servers; there you only publish the record and the policy file.
Step 1: publish a TLS-RPT record
Start with reporting, so you have data before enforcing anything. TLS-RPT works without MTA-STS too: reports then show no-policy-found.
_smtp._tls.example.com. 3600 IN TXT "v=TLSRPTv1; rua=mailto:tls-reports@example.com"
v=TLSRPTv1must come first.rua=is where reports go: amailto:address or anhttps:URL that accepts POST requests. You can list several, separated by commas.- Only one TXT record at
_smtp._tlsmay start withv=TLSRPTv1. With two, senders assume you don’t use TLS-RPT.
Unlike DMARC, RFC 8460 defines no authorization record for report addresses on another domain, so you can point rua straight at a reporting service.
Step 2: write the policy file
The policy is plain text, one key: value pair per line:
version: STSv1
mode: testing
mx: mx1.example.com
mx: mx2.example.com
max_age: 86400
| Field | Values | Notes |
|---|---|---|
version | STSv1 | Required. Put it on the first line — Google’s instructions require that. |
mode | testing, enforce, none | Required. |
mx | a host name or a *. wildcard | One line per pattern; required unless the mode is none. |
max_age | seconds, at most 31557600 (about a year) | Required. How long senders cache the policy. |
The mx lines must cover every host in your MX records. A wildcard replaces exactly one label: *.example.net matches mx1.example.net, but neither example.net nor a.mx.example.net. For Microsoft 365, Microsoft documents mx: *.mail.protection.outlook.com; if your MX host ends in mx.microsoft (Exchange Online domains with DNSSEC enabled), Microsoft says to list that host name in the policy instead. For other providers, copy the host names from your MX records or the provider’s documentation. Avoid a wildcard over your own domain, such as *.example.com: any host in it with a valid certificate would count as a valid MX (RFC 8461, section 10.4).
The modes: in testing, senders report failures through TLS-RPT but deliver anyway; in enforce, they don’t deliver to MX hosts that fail validation; none withdraws the policy cleanly.
max_age: a short value while testing means a mistake doesn’t linger in caches (Google accepts anything from 86400, one day). In production, RFC 8461 expects weeks or more, because a long cache narrows the first-contact window.
Step 3: host it on mta-sts.example.com
The file must be reachable at exactly this address:
https://mta-sts.example.com/.well-known/mta-sts.txt
RFC 8461, section 3.3, sets the rules:
- HTTPS with a valid certificate for
mta-sts.example.com(a*.example.comwildcard certificate also works), from a CA trusted by browsers and operating systems, not expired. - Status 200. Senders must not follow redirects — a redirect to
www, another path or another host means no policy. Content-Type: text/plain, which senders should check.- Small and fast. Senders may give up after about a minute or when the file exceeds 64 KB.
Any static hosting works, as long as it serves a certificate for mta-sts.example.com. The policy covers only that exact domain: mail to user@sub.example.com looks for _mta-sts.sub.example.com, never the parent.
Test it from a terminal. Without -L, curl doesn’t follow redirects — just like a sending server:
curl -sS -D - https://mta-sts.example.com/.well-known/mta-sts.txt
You should see status 200, a text/plain content type and your policy.
Step 4: publish the _mta-sts record
_mta-sts.example.com. 3600 IN TXT "v=STSv1; id=20261024T1200"
v=STSv1comes first.idis 1 to 32 letters and digits — no hyphens, dots or colons.id=2026-10-24is invalid, and an invalid record means no policy.- Exactly one record may start with
v=STSv1.
Publish the record after the file is reachable. Then run the MTA-STS checker: it reads the record, fetches and validates the policy file, and compares the mx lines with your MX records. The TLS-RPT checker verifies the _smtp._tls record and its report addresses.
Step 5: read the reports, then enforce
Participating senders send JSON reports covering a full UTC day, usually gzip-compressed, by email or HTTPS. Each report lists the policy the sender applied (sts, tlsa for DANE, or no-policy-found), counts of successful and failed sessions, and for failures a result-type with the sending IP, the MX host and the number of sessions.
| Result type | What to check |
|---|---|
starttls-not-supported | the MX doesn’t offer STARTTLS |
certificate-host-mismatch | the certificate doesn’t match the MX name required by the policy |
certificate-expired | renew the certificate on the MX |
certificate-not-trusted | self-signed certificate or incomplete chain |
sts-policy-fetch-error | the policy file is unreachable, redirected or not returning 200 |
sts-policy-invalid | a syntax error in the policy file |
sts-webpki-invalid | a certificate problem on mta-sts.example.com |
When the reports have been clean for a couple of weeks, switch to enforce:
- Edit the file: set
mode: enforceand a longermax_age, such as604800(one week) or more. - Then change the
idin the TXT record.
The order matters (RFC 8461, section 8.1): a sender that sees the new id while the old file is still being served would cache the old policy.
Changing the policy later
Every change to the file needs a new id, or senders keep their cached copy until max_age runs out. They notice a new id at their next refresh — the RFC suggests daily — and, in enforce mode, before giving up on a message.
Changing mail servers with enforce on: add the new MX hosts to the policy next to the old ones and update the id; give senders a few days to pick it up; switch the MX records; then remove the old hosts and update the id again. Or switch to testing for the migration — Microsoft recommends that when enforcement causes delivery problems.
Expired certificates: an expired MX certificate in enforce mode makes MTA-STS senders hold your mail. An expired certificate on the mta-sts host is less urgent — senders keep the cached policy and report sts-webpki-invalid — but fix it before those caches expire.
Removing MTA-STS: publish mode: none with a short max_age (say, a day), update the id, and wait until every cached policy has expired — up to the longest max_age you ever served. Only then delete the record and the file; deleting the TXT record alone doesn’t clear senders’ caches.
Common mistakes
- An invalid
id— punctuation, or more than 32 characters. - A redirect or the wrong certificate on the policy host, such as a blanket redirect to
https://www.example.comor the hosting platform’s default certificate. - An MX missing from the policy — often a backup MX or a newly added host.
- Editing the file without changing the
id. - Expecting it to protect outgoing mail. Your policy covers only mail sent to you.
If mail stops arriving after you switch to enforce, go back to mode: testing, update the id, and use the reports and the SMTP and TLS test to find the failing host.
References
- RFC 8461 — SMTP MTA Strict Transport Security (MTA-STS)
- RFC 8460 — SMTP TLS Reporting (TLS-RPT)
- RFC 3207 — SMTP Service Extension for Secure SMTP over TLS (STARTTLS)
- Google Workspace — About MTA-STS and TLS reporting
- Google Workspace — Create an MTA-STS policy
- Microsoft — Enhance mail flow with MTA-STS (Exchange Online)
- Microsoft — How SMTP DANE works (MTA-STS with mx.microsoft MX hosts)