MTA-STS not working? Fix the 7 errors senders report
MTA-STS breaks when DNS, HTTPS policy hosting, and MX TLS drift out of sync. This troubleshooting guide covers seven failures, the records to check first, and the commands that expose them.
We launched Receiver Shield a few weeks ago. Since then we have been processing TLS-RPT reports across our customer base, reading community forum threads, and reviewing broken MTA-STS deployments.
The protocol is small: two DNS TXT records, one HTTPS policy file, and sometimes one CNAME if a hosted policy service serves the file for you. The failures are usually operational. A policy can load in your browser and still fail for sending MTAs. One record can change while another stays stale. A bad cached policy may not hurt until days later, when a sender reuses it during delivery.
Use this as a triage order. Each failure links to a deeper troubleshooting guide with diagnosis commands and fixes.
The records to check first
Before chasing an individual TLS-RPT failure, verify the three public surfaces.
Your MTA-STS discovery record is a DNS TXT record at _mta-sts:
_mta-sts.example.com. 3600 IN TXT "v=STSv1; id=20260531090000Z;"
v=STSv1 must be the first tag. id is required by RFC 8461, must be 1 to 32 alphanumeric characters (RFC 8461 §3.1), and must change whenever the served policy content changes. If you edit mta-sts.txt but leave id unchanged, senders can keep using the old cached policy until max_age expires.
The policy file must be available at this exact HTTPS URL:
https://mta-sts.example.com/.well-known/mta-sts.txt
A minimal testing policy looks like this:
version: STSv1
mode: testing
mx: mx1.example.com
mx: *.example.net
max_age: 86400
mode is one of testing, enforce, or none. Use one mx: line per allowed MX pattern, except when mode: none is used. A wildcard only replaces the full left-most label, so *.example.net matches mx1.example.net but not mx1.mail.example.net.
TLS-RPT uses a separate DNS TXT record:
_smtp._tls.example.com. 3600 IN TXT "v=TLSRPTv1; rua=mailto:[email protected]"
rua is required. RFC 8460 allows both mailto: and https: report destinations. You can list multiple destinations separated by commas, but do not assume every sending provider will deliver a report to every destination.
Start with these DNS checks:
dig TXT _mta-sts.example.com +short
dig TXT _smtp._tls.example.com +short
dig MX example.com +short
dig CNAME mta-sts.example.com +short
Fetch the policy without following redirects, and surface both the status line and Content-Type header:
curl -sS -D - --max-time 10 https://mta-sts.example.com/.well-known/mta-sts.txt -o /dev/null
That prints only the headers. Drop -o /dev/null to see the body as well.
Do not use curl -L for this check. A browser-style redirect can hide the condition that makes policy fetches fail for sending MTAs. RFC 8461 §3.3 is explicit: HTTP 3xx redirects MUST NOT be followed, and only HTTP 200 is a valid response.
Check the certificate on the mta-sts subdomain itself:
openssl s_client -connect mta-sts.yourdomain.com:443 -servername mta-sts.yourdomain.com 2>/dev/null \
| openssl x509 -noout -subject -dates -ext subjectAltName
This is distinct from the MX server certificate check covered in issue 3 below.
1. sts-policy-fetch-error: the policy file is unreachable
TLS-RPT reports label this sts-policy-fetch-error (RFC 8460 §4.3.2.2). The sending server tried to fetch https://mta-sts.yourdomain.com/.well-known/mta-sts.txt and got something other than HTTP 200 with the policy content.
Typical causes:
-
Wrong path. The file must be at
/.well-known/mta-sts.txt, not/mta-sts.txtor anywhere else. - HTTP redirect. RFC 8461 §3.3 prohibits following redirects. If the HTTPS policy URL redirects to another host, path, or challenge page, some senders get a 301 and give up. The policy works in your browser (which follows redirects) but fails for MTAs (which must not).
-
Cloudflare Browser Integrity Check. Cloudflare’s BIC blocks requests with non-browser User-Agent strings. Mail servers use agents like
libwww-perl/6.68. The policy loads fine when you test it in Chrome, but MTAs get a challenge page instead of the policy file. -
GitHub Pages. Jekyll ignores directories starting with a dot. If you host on GitHub Pages without a
.nojekyllfile in the repository root, the/.well-known/path returns 404. -
Expired certificate on the
mta-stssubdomain. Themta-stssubdomain needs a valid CA-signed TLS certificate. If your Let’s Encrypt renewal did not include that subdomain, the certificate can expire while the rest of the site still works.
The diagnosis is always the same: check the status code and Content-Type first.
curl -sS -D - --max-time 10 https://mta-sts.yourdomain.com/.well-known/mta-sts.txt -o /dev/null
If that does not return HTTP 200 and Content-Type: text/plain, start there.
Policy file format requirements (causes of sts-policy-invalid)
A policy that returns HTTP 200 can still produce sts-policy-invalid (RFC 8460 §4.3.2.2) if the content itself is malformed.
Line endings cause more worry than failures. The prose of RFC 8461 §3.2 describes CRLF-separated key/value pairs, but the ABNF in the same section defines the terminator as LF / CRLF, so a Unix-generated file with bare LF is syntactically valid and conformant parsers must accept it. A validator that flags LF-only line endings is stricter than the spec. The format problems that actually produce sts-policy-invalid are malformed keys, a missing mx line, and out-of-range max_age values.
Content-Type is another. RFC 8461 §3.2 says senders SHOULD validate that the media type is text/plain. A server returning text/html or application/octet-stream can cause fetch rejection.
max_age must stay within range. The maximum value is 31557600 seconds (RFC 8461 §3.2). Google Workspace additionally requires max_age to be at least 86400 seconds and recommends 604800 to 1209600 during testing.
Redirects cause the same problem as with the fetch itself: RFC 8461 §3.3 says HTTP 3xx redirects MUST NOT be followed, so the canonical URL must serve the file directly.
If you do not want to run the policy host yourself, Receiver Shield serves it on the Pro plan. You point one CNAME at DMARCTrust; we handle the HTTPS endpoint, Content-Type, line endings, and certificate.
Our policy fetch failures guide walks through each cause with the exact fix.
2. “The MX host does not match any MX allowed by the STS policy”
This is the verbatim error Google’s postmaster tools and many validators surface when the mx: lines in your policy file do not match your actual MX DNS records. RFC 8460 §4.3 does not define a result type named mx-mismatch. What actually appears in TLS-RPT JSON is certificate-host-mismatch (RFC 8460 §4.3.1) when the mismatch is caught at the TLS handshake, or no delivery attempt at all when the MX host is simply not covered by the policy. Third-party validators label this with phrases like “uncovered MX records” or “MX mismatch” as a convenience label, not an RFC-defined type.
In enforce mode, senders refuse to deliver to any MX host not listed in the policy. Provider MX naming is where policies age badly. Managed providers can publish tenant-specific or regional hostnames, and a policy copied from a generic guide may not match what your domain actually uses today.
Microsoft 365 assigns MX records like yourdomain-com.mail.protection.outlook.com. For domains whose MX points directly to Exchange Online, use:
mx: *.mail.protection.outlook.com
Do not use mx: mail.protection.outlook.com; it does not match the tenant subdomain. Listing one exact tenant hostname can work today but is brittle if the MX target changes.
Google Workspace currently recommends smtp.google.com for new MX setup, while legacy aspmx... values remain supported. Do not copy a generic MTA-STS policy from an old guide. Run:
dig MX yourdomain.com +short
Then include the actual Google MX host or wildcard pattern your domain uses in the policy. For example, a domain whose MX target is smtp.google.com needs:
mx: smtp.google.com
Fastmail publishes two official MX records:
mx: in1-smtp.messagingengine.com
mx: in2-smtp.messagingengine.com
We did not find a current official Fastmail MTA-STS setup guide while updating this post. Treat those MX records as the DNS baseline, then verify STARTTLS and certificate behavior yourself.
Full diagnosis and per-provider patterns are in our MX and certificate mismatches guide.
3. certificate-host-mismatch: TLS cert does not cover the MX hostname
TLS-RPT reports show certificate-host-mismatch (RFC 8460 §4.3.1). The TLS certificate presented by your mail server during the SMTP STARTTLS handshake does not include the MX hostname in its Subject Alternative Names.
That certificate is separate from the certificate on the mta-sts subdomain in issue 1. This check is about the actual mail server that receives email.
Common scenario: your hosting provider’s mail server has a certificate for mail.hostingprovider.com, but your MX record points to mail.yourdomain.com. The certificate does not cover your hostname, so MTA-STS validation fails.
Diagnose it with:
printf 'QUIT\r\n' | openssl s_client -starttls smtp \
-connect mail.yourdomain.com:25 \
-servername mail.yourdomain.com \
-verify_hostname mail.yourdomain.com \
-verify_return_error
Then inspect the certificate names:
printf 'QUIT\r\n' | openssl s_client -starttls smtp \
-connect mail.yourdomain.com:25 \
-servername mail.yourdomain.com 2>/dev/null |
openssl x509 -noout -subject -issuer -dates -ext subjectAltName
If your hostname is not in the SAN list, contact your mail hosting provider. Large managed providers usually publish MX hostnames with matching STARTTLS certificates, but you should still verify the exact hostname your domain uses.
Our MX and certificate mismatches guide covers incomplete certificate chains and missing STARTTLS as well.
4. The policy ID is not updated after a change
This one is easy to miss because nothing fails at the moment you make the change.
MTA-STS requires three things to stay in sync:
- Your actual MX DNS records
- The
mx:entries andmodein yourmta-sts.txtpolicy file - The
idvalue in your_mta-stsDNS TXT record
When you change the policy file (for example, switching from mode: testing to mode: enforce), you must also change the id in the DNS TXT record. Senders cache the policy for max_age seconds. They only re-fetch when they see a new id. If the id stays the same, senders keep using the old cached policy.
With max_age: 604800 (7 days), your fix may not take effect for up to a week. With max_age: 2592000 (30 days), you may be waiting a month.
That is why Receiver Shield auto-generates the policy ID from the policy content. When you edit the policy in the dashboard, the id updates automatically. You still need to update your DNS TXT record, but the dashboard tells you when it is out of sync.
Our enforce mode and rollback guide covers the three-point sync rule in detail.
5. Jumping to enforce mode too early
Going straight to mode: enforce turns testing mistakes into delivery failures.
Microsoft Exchange Online documents specific NDR (non-delivery report) codes when MTA-STS enforcement blocks delivery, including:
-
5.4.8for MX validation failure -
5.7.5for remote certificate validation failure
If you see these bounce codes in your logs, enforce mode is rejecting mail from senders that cannot meet the TLS requirements. The immediate fix is to switch back to mode: testing, bump the id, and investigate.
max_age has traps in both directions during rollout:
-
Too high on first deploy. Some guides show
max_age: 31557600(1 year). If anything is misconfigured, senders who cached the broken policy keep using it for up to a year. Keep testing values conservative and increase once you are confident. Google Workspace documentation allowsmax_agefrom 86400 to 31557600 seconds and recommends 604800 to 1209600 seconds while testing. -
Too low. Google requires
max_ageto be at least 86400 seconds. If you setmax_age: 3600for quick testing, Google treats the policy as invalid.
Our enforce mode and rollback guide shows the emergency rollback sequence.
6. TLS-RPT reports are not arriving
You publish the _smtp._tls DNS record, wait a few days, and nothing arrives. This is normal and does not mean something is broken.
TLS-RPT reports come from the sending side. Only mail servers that have implemented RFC 8460 will send you reports. If your domain does not receive much email from reporting senders such as Google and Microsoft, you will see few reports.
A few things to rule out before blaming DNS:
-
Wrong
ruaaddress. A typo in themailto:value. Check withdig TXT _smtp._tls.yourdomain.com +short. -
Reports landing in spam. TLS-RPT reports often arrive as compressed JSON attachments. If your helpdesk or mailbox rules quarantine unknown
.json.gzfiles, the reports may be arriving but never reaching the person who expects them. -
Multiple destinations. RFC 8460 allows multiple comma-separated
ruadestinations, but senders are not required to guarantee delivery to every destination. Put your monitoring address first and test that reports arrive there.
TLS-RPT result types: what each one means
When reports do arrive, the table below maps each result type string to its RFC 8460 §4.3 definition and the most likely cause.
| Result type | RFC 8460 section | What happened | Likely cause | Debug command |
|---|---|---|---|---|
sts-policy-fetch-error |
§4.3.2.2 | Sender could not fetch the policy file | HTTP non-200, redirect, bad cert on mta-sts subdomain |
curl -sS -D - https://mta-sts.DOMAIN/.well-known/mta-sts.txt -o /dev/null |
sts-policy-invalid |
§4.3.2.2 | Policy fetched but could not be parsed | Wrong Content-Type, malformed key/value pairs, max_age out of range |
Fetch policy body and inspect with curl -sS https://mta-sts.DOMAIN/.well-known/mta-sts.txt
|
sts-webpki-invalid |
§4.3.2.2 | Web PKI validation failed for the policy host | Expired or untrusted cert on mta-sts subdomain |
openssl s_client -connect mta-sts.DOMAIN:443 -servername mta-sts.DOMAIN |
certificate-host-mismatch |
§4.3.1 | MX server cert SANs do not include the MX hostname | Shared hosting cert, or MX hostname differs from cert CN/SANs |
openssl s_client -starttls smtp -connect MX_HOST:25 -servername MX_HOST + inspect SANs |
certificate-expired |
§4.3.1 | MX server cert is past its expiry | Missed renewal on mail server cert | Same openssl command, check notAfter date |
certificate-not-trusted |
§4.3.1 | MX server cert chain not trusted by sender | Self-signed cert, missing intermediate | Same openssl command, inspect issuer chain |
starttls-not-supported |
§4.3.1 | MX server did not advertise STARTTLS | STARTTLS disabled or not installed on mail server |
openssl s_client -starttls smtp -connect MX_HOST:25, look for STARTTLS in EHLO response |
validation-failure |
§4.3.1 | STARTTLS negotiation failed for another reason | TLS handshake error; sender SHOULD include failure-reason-code in the report |
Check failure-reason-code field in TLS-RPT JSON for sender-specific detail |
Raw TLS-RPT is JSON, and reading it by hand gets tedious fast. Receiver Shield parses it automatically, grouping failures by type, sender, and MX host with trends over time. No manual .json.gz decompression required.
Our TLS-RPT report failures guide covers every failure type with diagnosis commands.
7. Improper MTA-STS removal
When you want to disable MTA-STS, deleting the DNS records and policy file feels natural. It is also the risky path.
Senders that previously fetched your enforce-mode policy have it cached. If the policy file disappears, those senders continue enforcing the cached version until max_age expires. If your MX hostnames or certificates change during that window, the cached policy no longer matches, and email bounces.
The correct procedure:
- Change the policy mode to
nonein the policy file - Update the
idin the_mta-stsDNS TXT record so senders re-fetch - Keep the policy file accessible for at least
max_ageseconds - Only then remove the DNS records
This is the MTA-STS equivalent of DMARC’s “do not jump from p=reject to removing the record.” Receiver Shield serves mode: none during safe teardown and rollback so senders can fetch the removal policy before records disappear.
Our enforce mode and rollback guide explains the full teardown sequence.
What tools check MTA-STS and TLS-RPT alongside DMARC and SPF?
Most checkers test one protocol at a time. The free domain checker at /domains runs DMARC, SPF, DKIM, MTA-STS, and TLS-RPT together. Paste your domain and you get a status for every layer at once, so you can see, for example, that MTA-STS is misconfigured while DMARC is already at p=reject.
The pattern behind these failures
Most of these issues have the same root cause: DNS, HTTPS policy hosting, and mail server TLS all have to agree, and MTA-STS does not give you immediate feedback when they drift. You make a change, and if something is wrong, you may only find out when a sender’s cache expires or when TLS-RPT reports arrive.
That feedback delay is what makes MTA-STS harder to operate than DMARC. With DMARC, aggregate reports often start arriving within a day once receivers send traffic. With MTA-STS, you publish records, host a policy file, configure TLS on your MX servers, wait for senders to fetch the policy, wait for TLS-RPT reports to accumulate, and then parse the JSON to see what happened.
Receiver Shield shortens that loop. It hosts the policy, parses TLS-RPT, and shows what would break before you enforce. A hosted deployment uses these records:
mta-sts.example.com. CNAME mta-sts-proxy.dmarctrust.com.
_mta-sts.example.com. TXT "v=STSv1; id=<generated_policy_id>;"
_smtp._tls.example.com. TXT "v=TLSRPTv1; rua=mailto:<generated DMARCTrust reporting address>"
DMARCTrust serves the policy at /.well-known/mta-sts.txt, generates the policy ID from the policy content, parses incoming TLS-RPT reports, and serves mode: none during safe teardown or rollback. New to MTA-STS? Start with the MTA-STS guide and run your domain through the free domain checker to see where you stand.