MTA-STS and TLS-RPT: step-by-step setup
Require encrypted delivery to your mail servers with MTA-STS (RFC 8461) and see TLS failures with TLS-RPT (RFC 8460), from testing mode to enforce.
The problem MTA-STS solves
When one mail server delivers to another, it looks up the MX records of the recipient's domain, connects on port 25 and upgrades to TLS with STARTTLS if the receiver offers it. If STARTTLS is missing or the certificate is invalid, most senders deliver in plain text anyway. That keeps mail flowing, but it also means an attacker who can tamper with the connection or with DNS can remove the STARTTLS offer and read the mail.
MTA-STS (SMTP MTA Strict Transport Security, RFC 8461) lets a receiving domain publish that it supports TLS and which MX hosts are legitimate. Sending servers that implement it cache the policy, then refuse to deliver over an unencrypted or unauthenticated connection while the policy is in enforce mode. TLS-RPT (RFC 8460) is the companion reporting standard: senders send you daily summaries of successful and failed TLS connections.
Before you start
MTA-STS only works if every MX host already accepts STARTTLS with a certificate that is publicly trusted and valid for the host name in the MX record. Hosted mailbox providers meet this for their own MX names. If you run your own mail server, check it first; a self-signed certificate or one issued for a different name will fail under enforce.
- List your MX hosts with the MX & SMTP.
- Confirm each MX host name is covered by its certificate. The TLS Checker reads the certificate on port 443; for port 25 use
openssl s_clientas shown below. - Decide where to host the policy file: a small static site, an object store behind HTTPS, or your existing web server.
- Choose an address or HTTPS endpoint for TLS reports, ideally a dedicated mailbox.
openssl s_client -starttls smtp -connect mail.example.com:25 -servername mail.example.com -verify_return_error </dev/null | openssl x509 -noout -subject -issuer -enddate -ext subjectAltNamePort 25 is often blocked locally
Step 1: publish TLS-RPT
Start with reporting, because it costs nothing and shows problems before you enforce anything. The record is a TXT record at _smtp._tls under your domain. The rua value is a mailto: or https: URI; several destinations are separated by commas.
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:tlsrpt@example.com"Reports are JSON documents, usually compressed with gzip and sent once a day by providers that support TLS-RPT. Each report lists the policy the sender found, the number of successful sessions, and failures grouped by type. Even without MTA-STS, reports show whether senders could negotiate TLS with your MX hosts.
| result-type | Meaning |
|---|---|
starttls-not-supported | The MX host did not offer STARTTLS. |
certificate-host-mismatch | The certificate does not cover the MX host name. |
certificate-expired | The certificate is past its expiry date. |
certificate-not-trusted | The certificate chain does not lead to a trusted root. |
validation-failure | Another validation error occurred. |
sts-policy-fetch-error | The sender could not fetch the MTA-STS policy file. |
sts-policy-invalid | The policy file was fetched but could not be parsed. |
sts-webpki-invalid | The HTTPS certificate of the policy host was not valid. |
Step 2: host the policy file
The policy is a short text file served at exactly https://mta-sts.<your domain>/.well-known/mta-sts.txt. The host mta-sts.example.com needs a DNS record pointing at your web server and a publicly trusted certificate for that name. Senders must not follow HTTP redirects when fetching the policy (RFC 8461 §3.3), so serve the file directly with status 200.
version: STSv1
mode: testing
mx: mail.example.com
mx: *.mx.example.net
max_age: 86400| Field | Values | Notes |
|---|---|---|
version | STSv1 | The only version defined so far. |
mode | testing, enforce, none | testing reports failures but still delivers. |
mx | Host name or *.domain | One line per MX pattern. A wildcard matches exactly one label. |
max_age | Seconds, up to 31557600 | How long senders cache the policy. Start small, raise later. |
A wildcard such as *.mx.example.net matches mx1.mx.example.net but not mx.example.net itself, and not a.b.mx.example.net. List every pattern your MX records use; a missing pattern makes delivery fail under enforce.
server {
listen 443 ssl;
server_name mta-sts.example.com;
ssl_certificate /etc/ssl/mta-sts.example.com/fullchain.pem;
ssl_certificate_key /etc/ssl/mta-sts.example.com/privkey.pem;
location = /.well-known/mta-sts.txt {
default_type text/plain;
return 200 "version: STSv1\nmode: testing\nmx: mail.example.com\nmax_age: 86400\n";
}
location / {
return 404;
}
}Verify the file from outside: curl -sS https://mta-sts.example.com/.well-known/mta-sts.txt should print the policy without a redirect, and the TLS Checker should show a valid certificate for the host.
Step 3: publish the _mta-sts record
The TXT record announces that a policy exists and carries an id. Senders compare the id with their cached policy and fetch the file again when it changes. The id is 1 to 32 letters and digits; a timestamp makes it easy to change on every update.
_mta-sts.example.com. IN TXT "v=STSv1; id=20260915T0900"Check it with the DNS Lookup using record type TXT for _mta-sts.example.com. There must be exactly one record starting with v=STSv1.
Change the id whenever the file changes
max_age expires, unless the id in DNS changes. Update the file first, then the id.Step 4: read reports, then enforce
Leave the policy in testing mode for at least a couple of weeks and read the TLS-RPT reports. The numbers you want are a steady count of successful sessions from the large senders and no failures other than occasional one-off network errors. Failures of type certificate-host-mismatch or sts-policy-fetch-error must be fixed before enforcing.
When the reports are clean, change mode to enforce, raise max_age (one to several weeks is common, for example 604800 for seven days), and update the id in DNS. From then on, supporting senders refuse to deliver to your domain over a connection that fails TLS validation, and they retry later instead of falling back to plain text.
version: STSv1
mode: enforce
mx: mail.example.com
mx: *.mx.example.net
max_age: 604800| Stage | TLS-RPT | MTA-STS mode | max_age |
|---|---|---|---|
| Reporting only | Published | Not yet | n/a |
| Testing | Published | testing | 86400 |
| Enforcing | Published | enforce | 604800 or more |
Reading a TLS-RPT report
A report is a JSON document describing one day of delivery attempts from one sending organisation. The policies array has one entry per policy the sender evaluated, with a summary of successful and failed sessions. When everything works, total-failure-session-count is zero and there is no failure-details array.
{
"organization-name": "Sender Example Inc.",
"date-range": { "start-datetime": "2026-09-14T00:00:00Z", "end-datetime": "2026-09-14T23:59:59Z" },
"contact-info": "smtp-tls-reporting@sender.example.net",
"report-id": "2026-09-14T00:00:00Z_example.com",
"policies": [{
"policy": {
"policy-type": "sts",
"policy-string": ["version: STSv1", "mode: testing", "mx: mail.example.com", "max_age: 86400"],
"policy-domain": "example.com"
},
"summary": { "total-successful-session-count": 1480, "total-failure-session-count": 12 },
"failure-details": [{
"result-type": "certificate-expired",
"receiving-mx-hostname": "mail.example.com",
"receiving-ip": "192.0.2.10",
"failed-session-count": 12
}]
}]
}Read the policy-string first: it shows exactly which policy the sender used, which reveals senders still holding an old cached version. Then look at each failure entry. The receiving-mx-hostname and receiving-ip tell you which of your servers failed, and the result-type tells you why.
A policy-type of no-policy-found means the sender did not find an MTA-STS or DANE policy for your domain. That is expected before you publish MTA-STS, and a sign of a DNS or hosting problem afterwards. Occasional small failure counts from a single sender can be network noise; repeated failures from several large senders are real problems.
Common mistakes
| Mistake | Effect | Fix |
|---|---|---|
Policy host redirects to www or HTTPS on another host | Senders cannot fetch the policy | Serve the file directly with status 200 |
Certificate for mta-sts.example.com missing or expired | sts-webpki-invalid failures | Add the name to your certificate automation |
| MX pattern missing from the file | Delivery refused to that MX under enforce | List every MX host or a matching wildcard |
File changed but id not updated | Senders keep the old cached policy | Change the id after every file change |
| Records deleted to turn it off | Cached enforce policies stay active | Publish mode: none first and wait |
| Enforcing without reports | Failures go unnoticed until mail is delayed | Publish TLS-RPT and read it during testing |
Most of these show up in TLS-RPT reports within a day, which is why the testing stage exists. Keep reports flowing after you enforce as well, because certificate expiry and MX changes are ongoing risks rather than one-time setup issues.
Operating it safely
Changing MX hosts
Before adding a new MX host or moving to a new provider, add its pattern to the policy, change the id, and wait at least the old max_age, so every sender has fetched the new policy. Only then change the MX records. Doing it in the other order makes senders with a cached policy refuse delivery to the new host.
Certificates
Under enforce, an expired certificate on an MX host stops delivery from supporting senders. Automate renewal for your MX hosts and for mta-sts.example.com, and monitor expiry dates. TLS-RPT reports certificate-expired failures, but by then mail is already delayed.
Turning MTA-STS off
Do not simply delete the records: senders keep enforcing the cached policy until it expires. Publish the file with mode: none, change the id, wait for the old max_age to pass, and then remove the TXT record and the file.
version: STSv1
mode: none
max_age: 86400MTA-STS and DANE
DANE for SMTP (RFC 7672) solves the same downgrade problem with TLSA records that pin the MX host's certificate or key in DNS. It relies on DNSSEC to make those records trustworthy, while MTA-STS relies on HTTPS and the public certificate authority system. Some senders support one, some the other, and some both.
If your domain is signed with DNSSEC and your mail provider supports DANE, publishing both is reasonable. If DNSSEC is not an option, MTA-STS gives you most of the protection with ordinary DNS and web hosting. The DNSSEC guide explains what signing a zone involves.
The two can coexist without conflict. A sender that supports DANE and finds valid TLSA records uses DANE; a sender that supports only MTA-STS uses your policy. TLS-RPT reports cover both, with the policy-type telling you which one a sender applied.
FAQ
Does MTA-STS protect mail I send?
No. Your policy protects mail sent to your domain by servers that support MTA-STS. Protection for your outgoing mail depends on the recipients' policies and on your sending platform supporting MTA-STS.
What happens in testing mode?
Senders validate TLS as they would under enforce and report failures through TLS-RPT, but they still deliver the message. It is designed for rolling out without risk.
Can the policy file be served through a redirect?
No. RFC 8461 says senders must not follow HTTP redirects when fetching the policy. Serve it directly with a 200 response from mta-sts.<domain>.
Do I need MTA-STS if my provider already uses TLS?
Your provider using TLS does not stop an attacker from stripping STARTTLS between the sender and your MX. MTA-STS is what tells senders not to accept that downgrade.
What max_age should I use?
Start with one day while testing. In enforce mode, one to several weeks is common; longer values protect better against attacks on the policy fetch but make changes slower to take effect.
Can I host the policy file on a CDN or static site?
Yes, as long as https://mta-sts.<domain>/.well-known/mta-sts.txt answers directly with status 200, a valid certificate for that host name and the policy as plain text. Check that the platform does not add a redirect to a trailing slash or to another host.
Do all senders support MTA-STS?
No. Many large mailbox providers validate it, but plenty of smaller servers do not. For them nothing changes: they deliver opportunistically as before, which is why MTA-STS is safe to add.
Does MTA-STS need a policy for every subdomain?
Policies apply to the exact recipient domain. Subdomains that receive mail with their own MX records need their own _mta-sts record and policy host if you want them covered.
Is TLS-RPT useful without MTA-STS?
Yes. Reports show whether senders could negotiate TLS with your MX hosts at all, which is a good health check before enforcing anything.