Skip to content

MTA-STS and TLS-RPT: step-by-step setup

In-depth guide. Updated .

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.

Delivery to a domain with MTA-STSThe sending server checks the _mta-sts TXT record, fetches the policy over HTTPS, then delivers only to a listed MX host over TLS with a valid certificate, and reports the result.1. Look up MX and _mta-sts.example.comTXT v=STSv1; id=20260915 tells the sender apolicy exists2. Fetch the policy over HTTPShttps://mta-sts.example.com/.well-known/mta-sts.txt,cached for max_age3. Check the MX hostThe MX name must match an mx: line in thepolicy4. STARTTLS with a valid certificateCertificate must be trusted and match the MXhost name5. Deliver or refuse, then reportenforce: no delivery on failure. Daily TLS-RPTreport to _smtp._tls rua
The sending server checks the _mta-sts TXT record, fetches the policy over HTTPS, then delivers only to a listed MX host over TLS with a valid certificate, and reports the result.

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.

  1. List your MX hosts with the MX & SMTP.
  2. 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_client as shown below.
  3. Decide where to host the policy file: a small static site, an object store behind HTTPS, or your existing web server.
  4. Choose an address or HTTPS endpoint for TLS reports, ideally a dedicated mailbox.
Check STARTTLS and the certificate on port 25
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 subjectAltName

Port 25 is often blocked locally

Many home and office networks block outbound port 25. Run the check from a server or cloud machine that is allowed to reach port 25.

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.

TLS-RPT record
_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.

Failure types you may see (RFC 8460 §4.3)
result-typeMeaning
starttls-not-supportedThe MX host did not offer STARTTLS.
certificate-host-mismatchThe certificate does not cover the MX host name.
certificate-expiredThe certificate is past its expiry date.
certificate-not-trustedThe certificate chain does not lead to a trusted root.
validation-failureAnother validation error occurred.
sts-policy-fetch-errorThe sender could not fetch the MTA-STS policy file.
sts-policy-invalidThe policy file was fetched but could not be parsed.
sts-webpki-invalidThe 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.

mta-sts.txt in testing mode
version: STSv1
mode: testing
mx: mail.example.com
mx: *.mx.example.net
max_age: 86400
Policy fields
FieldValuesNotes
versionSTSv1The only version defined so far.
modetesting, enforce, nonetesting reports failures but still delivers.
mxHost name or *.domainOne line per MX pattern. A wildcard matches exactly one label.
max_ageSeconds, up to 31557600How 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.

nginx server block for the policy host
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 TXT record
_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

Senders that cached the old policy keep using it until 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.

mta-sts.txt in enforce mode
version: STSv1
mode: enforce
mx: mail.example.com
mx: *.mx.example.net
max_age: 604800
Rollout summary
StageTLS-RPTMTA-STS modemax_age
Reporting onlyPublishedNot yetn/a
TestingPublishedtesting86400
EnforcingPublishedenforce604800 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.

Shortened TLS-RPT report
{
  "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

Mistakes that break MTA-STS
MistakeEffectFix
Policy host redirects to www or HTTPS on another hostSenders cannot fetch the policyServe the file directly with status 200
Certificate for mta-sts.example.com missing or expiredsts-webpki-invalid failuresAdd the name to your certificate automation
MX pattern missing from the fileDelivery refused to that MX under enforceList every MX host or a matching wildcard
File changed but id not updatedSenders keep the old cached policyChange the id after every file change
Records deleted to turn it offCached enforce policies stay activePublish mode: none first and wait
Enforcing without reportsFailures go unnoticed until mail is delayedPublish 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.

Retiring a policy
version: STSv1
mode: none
max_age: 86400

MTA-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.

Sources