MTA-STS and TLS-RPT: enforce encrypted email delivery to your domain

MTA-STS (RFC 8461) lets your domain tell sending mail servers that they must deliver to your MX hosts over TLS with a valid certificate, and must not fall back to unencrypted delivery. You publish it with a _mta-sts TXT record and a short policy file at https://mta-sts.<your-domain>/.well-known/mta-sts.txt. TLS-RPT (RFC 8460) is its companion: a _smtp._tls TXT record that asks senders to send you daily JSON reports on TLS successes and failures. Start in testing mode, read the reports, fix what they show, then switch to enforce.

Updated October 29, 2026

Why SMTP needs MTA-STS

Server-to-server email uses opportunistic TLS. Your MX advertises STARTTLS in its reply to EHLO, and the sending server upgrades the connection if it can (RFC 3207). If the extension is missing or the handshake fails, most senders simply deliver in plaintext, and most don't check whether the certificate is valid or matches the hostname.

220 mx1.example.com ESMTP
EHLO out.sender.example.org
250-mx1.example.com
250-PIPELINING
250-SIZE 52428800
250-STARTTLS
250 8BITMIME
A receiving server advertising STARTTLS. An attacker on the path can delete that line.

That leaves two easy attacks: strip STARTTLS from the EHLO reply so the sender never tries TLS, or spoof DNS so the sender connects to a different server. The sender notices neither. MTA-STS closes both gaps. You publish, over HTTPS authenticated by an ordinary web certificate, a policy listing your legitimate MX hosts. A sender that supports MTA-STS then requires TLS, requires a certificate that is valid for the MX hostname, and in enforce mode refuses to deliver rather than downgrade.

How MTA-STS, TLS-RPT and DANE fit together

MechanismWhere it is publishedWhat it doesNeeds DNSSEC
MTA-STS (RFC 8461)_mta-sts TXT record plus an HTTPS policy fileTells senders which MX hosts are valid and whether to require verified TLSNo
TLS-RPT (RFC 8460)_smtp._tls TXT recordAsks senders to report TLS successes and failures to you dailyNo
DANE (RFC 7672)TLSA records at _25._tcp.<mx-host>Pins the MX certificate or its issuer in DNSYes

For most domains, especially on hosted mailboxes, MTA-STS plus TLS-RPT is the practical setup because it needs only DNS records and a static web file. DANE is covered at the end of this guide. TLS-RPT works with either and is worth publishing on its own, since it shows you how senders experience TLS on your MX hosts.

Here is how a supporting sender uses the policy: it looks up _mta-sts.example.com, fetches and caches the policy file, looks up your MX records as usual, drops any MX host that doesn't match the policy's mx lines, and requires a valid certificate on the host it connects to. On later deliveries it rechecks the TXT record and fetches the file again only when the id has changed.

Before you start: check every MX host's TLS

MTA-STS only enforces what your MX hosts already do. Each host must advertise STARTTLS and present a certificate that is valid for its MX hostname, chains to a publicly trusted CA and has not expired. Self-signed certificates fail. List your hosts with the MX lookup, which also shows each host's IPv4 and IPv6 addresses, then test each one:

$ openssl s_client -starttls smtp -connect mx1.example.com:25 \
    -servername mx1.example.com -verify_hostname mx1.example.com -brief </dev/null
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Verification: OK
Verified peername: mx1.example.com
Run it for every MX host, including equal-preference peers and backups.

Hosted providers such as Google Workspace and Microsoft 365 already serve valid certificates on their MX hosts, so the work there is publishing the policy correctly. If you run your own servers or a filtering gateway in front of the provider, this check is where most problems surface.

Step 1: publish the MTA-STS policy file

The policy is a plain text file served at exactly https://mta-sts.example.com/.well-known/mta-sts.txt, where example.com is the domain in your recipients' addresses. It contains one key: value pair per line.

version: STSv1
mode: testing
mx: mx1.example.com
mx: mx2.example.com
max_age: 86400
A first policy in testing mode, cached for one day.
FieldValuesNotes
versionSTSv1Required, and must be the first line.
modetesting, enforce or nonetesting reports failures but still delivers. enforce refuses delivery to hosts that fail. none is used to retire a policy.
mxA hostname or *. wildcardOne line per pattern. Every MX host you publish must match one of them.
max_ageSeconds, up to 31557600How long senders may cache the policy. RFC 8461 expects weeks or more once you enforce.

A wildcard matches exactly one label on the left. mx: *.example.net matches mx1.example.net but not example.net itself and not a.b.example.net. For Microsoft 365, the documented pattern is mx: *.mail.protection.outlook.com. For Google Workspace, list what you publish: mx: smtp.google.com for the newer single record, or mx: aspmx.l.google.com plus mx: *.aspmx.l.google.com to cover the five legacy hosts.

  • The mta-sts hostname needs its own DNS record (an A record or a CNAME to your web host is fine here; the no-CNAME rule applies only to MX targets).
  • The HTTPS certificate must be valid for mta-sts.example.com specifically. A wildcard certificate for *.example.com covers it.
  • The URL must return 200 with the policy itself. Senders must not follow redirects, so an http to https or www redirect on that exact path breaks the fetch.
  • Serve it as text/plain. RFC 8461 tells senders to check the media type.
  • Any static host works: object storage behind a CDN, a small serverless function, or a static site with a custom domain. Single-page app hosts often return their index.html with a 200 for unknown paths, so confirm the body is the policy.

Step 2: publish the _mta-sts TXT record

The TXT record tells senders a policy exists and which version it is. Publish it at _mta-sts under the recipient domain:

_mta-sts.example.com.  3600  IN  TXT  "v=STSv1; id=20261029T0900"
  • v=STSv1 must come first.
  • id is 1 to 32 letters and digits. A timestamp works well because it is unique and tells you when the policy last changed.
  • Change the id every time you change the policy file. Senders with a cached policy only refetch the file when the id differs.
  • Publish exactly one record starting with v=STSv1. If senders find more than one, they treat the domain as having no policy.

MTA-STS is discovered per recipient domain. If people receive mail at @support.example.com, that name needs its own _mta-sts.support.example.com record and a policy at https://mta-sts.support.example.com/.well-known/mta-sts.txt.

Step 3: publish a TLS-RPT record

TLS-RPT is a single TXT record at _smtp._tls. The rua tag says where reports go: a mailto: address, an https: endpoint that accepts posted JSON, or both separated by a comma.

_smtp._tls.example.com.  3600  IN  TXT  "v=TLSRPTv1; rua=mailto:tls-reports@example.com"

Publish it before or with the MTA-STS policy so you have data from the start of testing. Use a mailbox that accepts compressed attachments, because reports usually arrive as gzipped JSON. If you already process DMARC aggregate reports (how to read DMARC reports), sending TLS reports to the same pipeline keeps everything in one place.

Testing vs enforce: a safe rollout

  1. Confirm STARTTLS and a valid certificate on every MX host, as shown above.
  2. Publish the TLS-RPT record.
  3. Publish the policy in mode: testing with a short max_age such as 86400, then the _mta-sts TXT record.
  4. Collect reports for at least two weeks. Look for failures on any host, especially backups that rarely receive traffic.
  5. Fix what the reports show and test the affected hosts directly.
  6. Switch the file to mode: enforce with a moderate max_age such as 604800 (one week), and publish a new id.
  7. Once enforce has run cleanly, raise max_age to several weeks or more, again with a new id.

Testing mode is there to surface certificate and MX mismatches without blocking mail. A quiet report period is not proof every fallback host was exercised, though. A secondary MX with a broken certificate chain only shows up in reports when senders actually reach it, so test infrequently used hosts directly before you enforce.

In enforce mode, a supporting sender that cannot validate an MX host skips it and tries the others. If none passes, it queues the message, retries, and eventually bounces it if nothing changes. When a sender reports such a delay, paste the notice into the bounce analyzer to see which MX and error it hit, or read how to read a bounce message. A short max_age early on limits how long a mistake stays cached.

Verify the setup end to end

Check both DNS records and the exact policy URL. A DNS-only check cannot tell you whether the policy can be fetched and parsed.

$ dig +short TXT _mta-sts.example.com
"v=STSv1; id=20261029T0900"
$ dig +short TXT _smtp._tls.example.com
"v=TLSRPTv1; rua=mailto:tls-reports@example.com"

$ curl -sS -D - https://mta-sts.example.com/.well-known/mta-sts.txt
HTTP/2 200
content-type: text/plain

version: STSv1
mode: testing
mx: mx1.example.com
mx: mx2.example.com
max_age: 86400
curl does not follow redirects without -L, so a 301 here is a real failure.
  • Every host from dig +short MX example.com matches an mx line in the policy.
  • The policy response is 200, text/plain, not a redirect, and the body is the policy rather than an HTML page.
  • The certificate on mta-sts.example.com is valid with normal verification on (no -k).
  • Each MX host passes the openssl s_client check with Verification: OK.

Then send yourself mail from an outside account and check the receiving hop's Received header in the header analyzer. It should show ESMTPS and a TLS version.

Reading TLS-RPT reports

Supporting senders, Google among them, send one report per day covering a UTC day. By email it arrives with a subject such as Report Domain: example.com Submitter: sender.example Report-ID: <...> and a gzipped JSON attachment. Inside, each policy the sender applied has a summary and, if anything failed, failure details.

{
  "organization-name": "Sender Example Inc.",
  "date-range": {
    "start-datetime": "2026-10-27T00:00:00Z",
    "end-datetime": "2026-10-27T23:59:59Z"
  },
  "contact-info": "smtp-tls-reporting@sender.example",
  "report-id": "2026-10-27T00:00:00Z_example.com",
  "policies": [{
    "policy": {
      "policy-type": "sts",
      "policy-string": ["version: STSv1", "mode: testing",
        "mx: mx1.example.com", "mx: mx2.example.com", "max_age: 86400"],
      "policy-domain": "example.com"
    },
    "summary": {
      "total-successful-session-count": 4210,
      "total-failure-session-count": 37
    },
    "failure-details": [{
      "result-type": "certificate-expired",
      "sending-mta-ip": "198.51.100.7",
      "receiving-mx-hostname": "mx2.example.com",
      "receiving-ip": "203.0.113.26",
      "failed-session-count": 37
    }]
  }]
}
Illustrative report: every failure is on mx2, the backup, with an expired certificate.

policy-type is sts, tlsa (DANE) or no-policy-found. policy-string shows the policy the sender actually used, which matters during changes because it may be an older cached version. Group failures by receiving-mx-hostname and result-type to find the specific endpoint and fault.

result-typeWhat failedWhere to fix it
starttls-not-supportedThe MX did not offer STARTTLSSMTP server or gateway config
certificate-host-mismatchCertificate does not cover the MX hostnameSMTP certificate
certificate-expiredSMTP certificate past its expirySMTP certificate renewal on that host
certificate-not-trustedChain doesn't reach a trusted CA (often self-signed or missing intermediate)SMTP certificate chain
validation-failureOther validation problemRead failure-reason-code or additional-information if present
sts-policy-fetch-errorSender could not fetch the policy fileWeb host for mta-sts. (404, redirect, timeout)
sts-policy-invalidPolicy fetched but invalid, or MX not coveredPolicy file syntax and mx lines
sts-webpki-invalidPolicy host's HTTPS certificate failed validationWeb certificate for mta-sts.
tlsa-invalid, dnssec-invalid, dane-requiredDANE problemsTLSA records or DNSSEC chain
Result types defined in RFC 8460.

Keep certificate failures and policy failures apart: they live on different systems, often owned by different teams. One report can contain both a policy fetch error and an expired SMTP certificate, and renewing the web certificate does nothing for the mail server. Reports also describe what particular senders saw at a particular time, so compare their timestamps with your change log before matching them to today's live checks. If you use HealthCheck Email for DMARC report monitoring, it can receive and parse TLS-RPT reports in the same place.

Policy not found or can't be fetched

The most common broken setup has a correct TXT record and no working policy file. Discovery succeeds, retrieval fails, and reports show sts-policy-fetch-error. A working homepage on the mta-sts host proves nothing; only the exact well-known URL counts.

  • The file was never deployed, or the deploy dropped dot-folders such as .well-known.
  • The host returns an HTML error page or an app shell with status 200, which senders fail to parse (sts-policy-invalid).
  • A redirect sits in front of the file: http to https, apex to www, or a trailing-slash rule.
  • No DNS record exists for mta-sts.example.com, or it points at a host that doesn't serve that name.

The web certificate is a separate failure point from the SMTP certificate. A valid MX certificate does not help if the certificate on mta-sts.example.com has expired, doesn't include that name, or isn't served because the host lacks an SNI binding for it. Reports show this as sts-webpki-invalid. Check it directly, and never declare the policy healthy with certificate verification turned off:

$ openssl s_client -connect mta-sts.example.com:443 -servername mta-sts.example.com </dev/null 2>/dev/null \
    | openssl x509 -noout -subject -enddate -ext subjectAltName

When a fetch fails, a sender with a valid cached policy keeps using it, and a sender with nothing cached proceeds as if no policy exists. So a broken policy host usually weakens protection quietly instead of blocking mail, which is why the reports matter.

MX certificate and STARTTLS failures

Hostname mismatch: a server can complete a TLS handshake while presenting a certificate for a different name. If DNS routes senders to mx.example.com and the server presents a certificate only for panel.example.com, encryption works but identity verification fails, and an enforcing sender won't deliver. The name that matters is the MX hostname the sender connected to, not the domain in the From address.

$ openssl s_client -starttls smtp -connect mx.example.com:25 \
    -servername mx.example.com -verify_hostname mx.example.com -brief </dev/null
Verification error: hostname mismatch

Expired certificates: check every advertised endpoint, not one. A common pattern is a primary MX that renews automatically and a backup that still holds last year's certificate, so failures appear only when senders reach the backup. Equal-preference peers behind separate addresses can drift the same way, and a load balancer's main address can hide an expired certificate on one node. After deploying the renewal, watch queues and the next TLS reports for recovery. How mail behaves depends on each sender's policy, so an expired certificate rarely fails everything identically.

STARTTLS not advertised: if EHLO no longer lists STARTTLS, the session cannot be upgraded and reports show starttls-not-supported. Upgrades to SMTP proxies and filtering gateways are the usual cause: the gateway's listener has TLS disabled while the backend behind it still supports it, and outside senders only ever see the gateway. Compare the EHLO reply on each MX and network path before suspecting interception; one missing capability can also come from configuration or a transient fault.

Changing MX hosts or the policy: caching and transitions

An enforcing policy blocks delivery to any MX host it doesn't cover, so MX changes and policy changes must be coordinated. The complication is caching: senders keep a policy for up to max_age and only refetch when they see a new id. Deleting the TXT record does not cancel a cached policy either; senders keep applying it until it expires. During a change, different senders evaluate your MX against different policy versions.

  • Adding an MX host: put it in the policy file, publish a new id, then change MX records.
  • Removing an MX host: change MX records first, keep the old host listed until at least one max_age has passed, then remove it with a new id.
  • Editing the file without changing the id is the most common mistake: cached senders have no reason to refetch, so the new MX line may be ignored for days.
  • A new id is a signal, not a guarantee. Senders check it when they next deliver to you, so lightly used senders refresh later.
WhenActionWhy
Day 0Add mx: mx.newhost.example to the policy and publish a new idSenders learn the new host before it receives mail
Day 0 + max_ageSwitch MX records to the new hostEvery cache that held the old policy has expired
LaterRemove the old mx line and publish a new idThe old host no longer receives mail
ThroughoutWatch TLS-RPTConfirms senders validate the new host
A provider migration under an enforcing policy.

If you can't wait a full max_age, switch to mode: testing with a new id first, wait for senders to pick it up, make the MX change, then return to enforce with another new id. Save every policy version with its id and publication time; when a report shows sts-policy-invalid for a host you just added, its policy-string tells you the sender was still on the old version. The email DNS change checklist and MX records explained cover the MX side of a migration.

To retire MTA-STS, publish mode: none with a new id and keep serving it for at least the previous max_age before deleting the file and TXT record. Senders that see none drop the old policy.

TLS-RPT reports aren't arriving

A TLS-RPT record requests reports; it doesn't guarantee them. Not every sender produces reports, and a low-volume domain may only hear from a few large providers. Before assuming nobody reports, check the plumbing:

  • Resolve _smtp._tls.example.com and check the version (v=TLSRPTv1) and the rua syntax, including the mailto: or https: prefix.
  • Confirm the reporting mailbox still exists. A renamed or deleted address silently drops every report while mail flow continues.
  • Make sure the mailbox or spam filter accepts gzipped JSON attachments, and that an https collector accepts the posted format.
  • Compare with earlier periods: which organizations reported before, and has inbound volume from them changed?

No reports does not mean no TLS failures. Keep the direct openssl checks on every MX host and the policy URL alongside passive reporting.

DANE and TLSA records with DNSSEC

DANE for SMTP (RFC 7672) takes the other route: instead of a web-hosted policy, you publish TLSA records that pin each MX host's certificate or its issuing CA, and senders trust them because DNSSEC signs them. Both the recipient domain's MX answer and the TLSA records must validate under DNSSEC.

_25._tcp.mx1.example.com.  IN  TLSA  3 1 1 8f2c...e41a

# SHA-256 of the certificate's public key, for a 3 1 1 record
$ openssl x509 -in mx1.pem -noout -pubkey | openssl pkey -pubin -outform DER \
    | openssl dgst -sha256
3 1 1 = match the server's own key (DANE-EE), by public key, using SHA-256.

A TLSA record without a valid DNSSEC chain gives no DANE assurance at all. A frequent failure: after a DNS provider migration, a stale DS record at the registrar no longer matches the new signing keys, so validating resolvers return SERVFAIL. The TLSA bytes still match the certificate, but the trust chain is broken and DANE senders defer mail. Validation outcomes come in three kinds: secure (signed and valid), insecure (provably unsigned) and bogus (signed but failing). Only secure supports DANE, and bogus is the one that stops mail.

  • Check validation with a validating resolver: dig +dnssec TLSA _25._tcp.mx1.example.com and look for the ad flag, or use delv.
  • Compare dig +short DS example.com with the zone's DNSKEY records when you see SERVFAIL.
  • Fix the DNSSEC chain through the DNS operator; changing TLSA data does not repair it.
  • On certificate renewal, publish the new TLSA record alongside the old one before you deploy the new key. A 3 1 1 record only survives renewal if the key stays the same.

You can publish DANE and MTA-STS together, and TLS-RPT reports on both (policy-type: tlsa). Because DANE ties certificate and DNS changes together, make sure whoever renews certificates and whoever runs DNSSEC coordinate.

Sources and further reading

Common questions

Do Gmail and Microsoft 365 honor MTA-STS?+

Yes. Google and Microsoft both document MTA-STS validation for mail their services send to domains that publish a policy. Neither hosts the policy file for your domain, so you publish the TXT record and serve the file yourself even when your mailboxes are hosted with them.

Is MTA-STS part of the Gmail and Yahoo sender requirements?+

No. Those rules cover authentication (SPF, DKIM and DMARC), one-click unsubscribe and spam rates for mail you send. MTA-STS protects mail you receive. Google's sender guidelines do ask senders to use TLS when transmitting mail. The bulk sender requirements guide has the full list.

Can mta-sts.example.com be a CNAME to my hosting provider?+

Yes. The policy host is an ordinary HTTPS site, so a CNAME to a static host or CDN is fine, as long as the certificate it serves is valid for mta-sts.example.com and the well-known path returns the policy with no redirect. The no-CNAME rule applies only to MX targets.

What max_age should I use?+

Use about a day (86400) while testing, about a week (604800) when you first enforce, then several weeks or more once things are stable. The maximum is 31557600 seconds, about a year. Longer values protect better against attacks at refresh time but make mistakes and MX changes slower to roll out.

Does MTA-STS slow down or block my incoming mail?+

Not when the MX hosts and policy are correct: senders cache the policy and check one TXT record per delivery. It only blocks mail in enforce mode when a host fails validation or isn't listed in the policy, and testing mode with TLS reports exists to catch exactly those cases first.