Skip to content

MTA-STS & TLS-RPT Checker

How the checker follows what a sending server does, from the _mta-sts record to the policy file, MX coverage and TLS-RPT, every rule applied along the way, what each finding means for mail in transit, and how to fix and verify each one.

Open Markdown

The tool page is tamperbox.dev/mta-sts-checker. It opens on a live check of tamperbox.dev; replace that domain to inspect your own. This page is the long version: what a sending server checks, every rule the tool applies at each step, what each finding means, and how to fix and verify each one.

Where processing happens: a domain is sent to the Tamperbox server, which asks public DNS for the _mta-sts record, the MX records and the _smtp._tls record, and fetches one URL over HTTPS: https://mta-sts.<domain>/.well-known/mta-sts.txt. A pasted policy file is read line by line in your browser. Nothing is stored.

MTA-STS lets a receiving domain tell sending servers: deliver only to these mail servers, and only over TLS with a valid certificate. TLS-RPT lets senders report when they could not. The tool answers:

  1. Is a policy announced? The _mta-sts TXT record with its id.
  2. Can the policy be fetched, and is it valid? The file at the well-known URL, its version, mode, mx lines and max_age.
  3. Does the policy cover every mail server? Each MX host against the policy’s mx lines.
  4. Will you hear about failures? The _smtp._tls TLS-RPT record and its report addresses.
  5. What should the policy say? A suggested file in enforce mode that covers every MX host.

It does not connect to any mail server, so STARTTLS support and MX certificates are not tested.

example.com. When you stop typing, or on Enter, the server makes the three DNS lookups and the one fetch in parallel. When all four fail because the lookup service is unavailable, the page reports an error rather than a missing policy.

Paste the contents of mta-sts.txt (version: STSv1, mode: enforce, mx: …, max_age: …). It is checked in the browser, shown as “Policy file (pasted)”. Publication, HTTPS hosting, MX coverage and TLS-RPT are not checked for a pasted file.

Paste v=STSv1; id=… and only the record is checked, with a reminder that the policy itself lives in a file on HTTPS.

Drop a .txt file anywhere on the page, or use Open file. It is read in the browser.

The verdict names the outcome: no record, not protected (the file could not be fetched), the check failed with the first failure, policy withdrawn, testing only, enforced, or, for a pasted file, policy file checked. The chips show the mode, how many MX servers the policy covers, and the number of findings; each one is a button that scrolls to the section that explains it.

Everything found, worst first; passes fold into one line. The finding reference lists them all.

Links that carry a derived value into another tool: the TLS certificate of the primary MX server on port 25, DANE records for the same host and port, and DNSSEC on the zone. Each opens the destination with the value already in its box; nothing is put in the URL.

History logs every Break it and Heal it change with what it replaced; Revert undoes the newest, Reset input returns to what you entered. Heal it offers the repairs the tool found for a pasted file: add the version line, correct a misspelt mode, set max_age to one week.

The four steps a sending server takes, in order, each with its status, what it found and the record or file it read: the policy record, the policy file, MX coverage, TLS reports.

One row per MX host with its preference, the policy line that covers it or “No matching line”, and Covered or Not covered.

A policy in enforce mode built from the current one: existing mx lines that still match an MX host, every uncovered host added by name, and a max_age of a week or the current value when it is longer and valid. Hidden when no mx line can be derived. The note under it says to serve the file over HTTPS and change the id in the record afterwards.

The checker follows the order in which a sending server discovers and applies a policy. Each rule below names the section of the specification it comes from; rules with no section are Tamperbox recommendations and are labelled as such.

Source: RFC 8461 section 3.1. The record is read at _mta-sts.<domain>, a CNAME at that name is followed, and a record split into several strings is joined without spaces, as section 3.1 requires. Records that do not begin with v=STSv1 are discarded, and the rest must number exactly one. The section is explicit about what happens otherwise: “If the number of resulting records is not one, or if the resulting record is syntactically invalid, senders MUST assume the recipient domain does not have an available MTA-STS Policy.”

Zero or two records give “Publish exactly one MTA-STS record.” Within the record, v must be the first tag (“The TXT record MUST begin with the sts-version field”) and id must be 1 to 32 letters or digits, the 1*32(ALPHA / DIGIT) rule of the section 3.1 grammar, so an id written with dashes fails. A missing record is FAIL, No record at _mta-sts.<domain>, with a suggested record whose id is today’s date followed by 01. A lookup that could not be made (as opposed to one that returned nothing) is reported as unavailable and produces no finding.

Source: RFC 8461 sections 3.2 and 3.3. The server fetches one URL only, https://mta-sts.<domain>/.well-known/mta-sts.txt, the fixed path of section 3.2. It reports a failure when:

  • the response is a redirect: “HTTP 3xx redirects MUST NOT be followed” (section 3.3);
  • the status is not a success (section 3.3 accepts only 200; see where the tool differs);
  • the Content-Type is not text/plain: “senders SHOULD validate that the media type is “text/plain”” (section 3.2);
  • the body exceeds 64 KiB, the size section 3.3 suggests;
  • the whole lookup takes longer than eight seconds (section 3.3 allows a timeout and suggests one minute).

Two refusals are Tamperbox safety rules with no RFC source: the host must resolve, and only to public addresses. No cookies, credentials or visitor headers are forwarded. A failed fetch gives FAIL, “No policy file”, with the reason in the chain, and the verdict “Not protected”. Section 3.3 states what a sender then does: with no cached policy, “senders MUST continue with delivery as though the domain has not implemented MTA-STS.”

Source: the field list and grammar of RFC 8461 section 3.2. Each line must be key: value; any other line is FAIL, “Not a key: value line: X”.

Rule Severity Title Source
version: STSv1 required FAIL version: STSv1 is missing 3.2
mode must be enforce, testing or none FAIL mode: X 3.2
mode: testing CHECK mode: testing 5; CHECK is Tamperbox’s severity
mode: enforce with no other problem PASS mode: enforce 5
At least one mx: line unless the mode is none FAIL No mx: lines 3.2 grammar
Each mx: a host name or *. plus a host name, at most 253 characters FAIL Invalid MX pattern X 3.2, RFC 5321 4.1.2
max_age a whole number of seconds from 0 to 31557600 FAIL max_age is missing or out of range 3.2
max_age under 86400 CHECK max_age N s none (Tamperbox recommendation)
Repeated version, mode or max_age: first value wins CHECK Duplicate X field 3.2

Section 5 defines what each mode makes a sender do. Under enforce, “Sending MTAs MUST NOT deliver the message to hosts that fail MX matching or certificate validation or that do not support STARTTLS.” Under testing, “messages may be delivered as though there were no MTA-STS validation failure”, which is why testing is a CHECK and not a PASS.

Source: RFC 8461 section 4.1. The MX records are sorted by preference, lowest first, as RFC 5321 section 5.1 orders them, and every host is compared with the policy’s mx patterns, case-insensitively and ignoring a trailing dot. Section 4.1 limits the wildcard: “the wildcard character ‘*’ may only be used to match the entire left-most label in the presented identifier.” So *.mx.example.net matches a.mx.example.net, never mx.example.net or b.a.mx.example.net.

An uncovered host is FAIL under mode: enforce (“X is not in the policy”: senders refuse to deliver to it, section 5) and CHECK otherwise (it would be refused once the policy enforces). Every host is checked, not only the preferred one, because section 8.4 warns that a misconfigured backup MX may only be discovered when the primary fails.

A domain with no MX records, a failed MX lookup or a null MX (the single 0 . record of RFC 7505 section 3, which says the domain accepts no mail) is FAIL, “MX coverage not established”.

Source: RFC 8460 section 3. The record is read at _smtp._tls.<domain>; records that do not begin with v=TLSRPTv1 are discarded and the rest must number exactly one: “If the number of resulting records is not one, senders MUST assume the recipient domain does not implement TLSRPT.” v must come first and at least one rua destination must be present. Section 3 names the two supported schemes, “mailto” and “https”, and the tool requires each destination to use one of them.

A missing, duplicated or unparseable record is CHECK, “No TLS-RPT record”, with a suggested record; a destination with another scheme is FAIL, “Invalid report address X”; a valid record is PASS, “TLS reports on”. Reporting is optional in the specification, so its absence is not a FAIL.

The suggested file is a Tamperbox construction, not an RFC rule. It is built only when at least one mx line can be derived. It uses mode: enforce, keeps the existing mx lines that still match an MX host (all of them when no MX hosts were read), adds every uncovered host by name, and sets max_age to the current value when it is valid and longer than a week, 604800 otherwise. The week follows section 3.2, which expects max_age “typically be in the range of weeks or greater”. The note under it asks you to change the id after publishing the file, in the order section 8.1 gives: “Recipients SHOULD also update the HTTPS policy body before updating the TXT record”.

The checker implements the discovery and policy rules of RFC 8461, the record rules of RFC 8460, and the MX rules of RFC 5321 and RFC 7505 that coverage depends on. Where the work happens:

  • Looked up on our server. The _mta-sts, MX and _smtp._tls records are resolved by the Tamperbox server through one public DNS-over-HTTPS resolver, following CNAME chains of up to eight hops.
  • Fetched on our server. The policy file is fetched once over HTTPS by the Tamperbox server, which returns the text to your browser.
  • Parsed locally. The record grammar, the policy file, MX coverage, TLS-RPT and the suggested policy are all evaluated in your browser, by the same code that checks a pasted file.

It never opens an SMTP connection, so everything that happens between a sender and an MX host is outside what it can see.

RFC 8461, SMTP MTA Strict Transport Security

Section titled “RFC 8461, SMTP MTA Strict Transport Security”

Status: Proposed Standard, September 2018, with no updating RFC.

Section Requirement What the tool does
3.1 One v=STSv1 TXT record, version first, id of 1 to 32 letters or digits, strings joined, CNAMEs followed Implemented as written for the version, id, count, joining and CNAMEs
3.2 Fixed URL; text/plain (SHOULD); version, mode, max_age once, mx at least once unless mode is none Implemented; the media type check is a hard failure, not a warning
3.3 Certificate valid for the mta-sts host; only 200; no redirects; no HTTP caching; timeout and size MAY Redirects refused, 64 KiB cap, eight-second limit; the certificate is not inspected (below)
3.3, 5.1 Senders cache a policy for up to max_age and apply a cached policy when discovery fails Not modelled: each check is live and uncached; the verdict notes that cached policies may still apply
3.4 Never fetch a policy from the parent zone Only the domain entered is checked
4.1 Every MX matches an mx pattern; the wildcard covers one left-most label Implemented for every MX host
4.2, 7.1, 7.2 STARTTLS, a valid MX certificate, SNI, TLS 1.2 or later Not tested; Take it further opens the TLS and DANE checks for the primary MX
5 Meaning of enforce, testing and none Drives the verdict and the severity of uncovered hosts
8.3 mode: none withdraws the policy Reported as a valid withdrawal, “Policy withdrawn”

Section 3.3 says the Policy Host “MUST present an X.509 certificate that is valid for the “mta-sts” DNS-ID”. The tool does not examine that certificate. The fetch relies on the TLS validation of the server platform, and a failed handshake surfaces as a generic lookup failure in the chain, not as a named certificate finding. Use the SSL checker on mta-sts.<domain> to see the certificate itself.

These differences were confirmed by running the parser on the inputs described.

Section What the RFC says What the tool does
3.2 A duplicated version, mode or max_age is not an error: “all entries except for the first SHALL be ignored” CHECK, “Duplicate X field”; the first value is kept, so testing followed by enforce remains testing
3.2 Field names are case-sensitive (%s"mode") and no space is allowed before the colon Names are matched case-insensitively and a space before the colon is accepted, so Mode : enforce passes here
3.2 Unknown fields “SHALL be ignored”; names may contain digits, _, - and . Unknown names with only letters and _ are ignored; a name with a digit, - or . is FAIL, “Not a key: value line”
3.1 Extension tags in the TXT record are allowed and ignored A tag name with - or . is reported as a malformed record; spaces around = are accepted
3.2 An mx value is an RFC 5321 Domain, which may be a single label Single-label patterns are FAIL, “Invalid MX pattern”
3.3 “Policies fetched via HTTPS are only valid if the HTTP response code is 200 (OK).” Any 2xx status is accepted

The bounds match section 3.2: a non-negative integer up to 31557600. The CHECK for values under 86400 is a Tamperbox recommendation; the RFC sets no lower bound, so max_age: 0 is valid there and a CHECK here. Section 3.2 expects “weeks or greater”, and section 10.2 says implementers “SHOULD prefer policy “max_age” values to be as long as is practical”, which is where the one-week suggestion comes from.

Status: Proposed Standard, September 2018.

Section Requirement What the tool does
3 One record at _smtp._tls, beginning v=TLSRPTv1, strings joined Implemented
3 rua required, a comma-separated list of mailto or https URIs Implemented; each destination is checked for one of the two schemes
3 Unknown fields “SHALL be ignored” A field name containing - or . makes the record unparseable here, reported as “No TLS-RPT record”
3 Reports by mail carry a DKIM signature; the key SHOULD declare s=tlsrpt Not checked
4, 5 Report format and delivery Out of scope: no reports are received or read

Two severity choices are Tamperbox’s own. A duplicated or invalid record is folded into the CHECK “No TLS-RPT record” rather than named, because the RFC’s consequence is the same as a missing one. An unsupported scheme is FAIL, although the RFC only says which schemes are supported; senders would have nowhere usable to send that report.

RFC 5321 (Draft Standard, October 2008, updated by RFC 7504) defines how senders find mail servers. Section 5.1 says MX preference “MUST be used in sorting”, and the coverage table follows that order. The same section says that when no MX records exist, “the address is treated as if it was associated with an implicit MX RR, with a preference of 0, pointing to that host.” The tool does not model the implicit MX: a domain without MX records is FAIL, “MX coverage not established”, and the domain itself is not compared with the mx lines.

RFC 7505 (Proposed Standard, June 2015) defines the null MX. Section 3 says “A domain that advertises a null MX MUST NOT advertise any other MX RR.” The tool treats any . exchange as a null MX and stops; it does not report a null MX mixed with ordinary records as a separate error.

RFC 8461 sections 3.3, 4.1 and 4.2 refer to RFC 6125 for name matching. RFC 9525 (Proposed Standard, November 2023) obsoletes RFC 6125, so its rules now apply. Section 6.3 compares names label by label “using a case-insensitive ASCII comparison” and states that “A wildcard in a presented identifier can only match one label in a reference identifier.” The mx matching applies both rules. RFC 8461 also requires the A-label form for internationalized names, and a pattern with non-ASCII characters is reported as an invalid MX pattern. Certificate name matching, the main subject of RFC 9525, is not performed, because no certificate is examined.

_mta-sts is listed in the “Underscored and Globally Scoped DNS Node Names” registry created by RFC 8552 section 4.1 (Best Current Practice, BCP 222). RFC 8553, the companion that corrected older specifications, does not update RFC 8461 or RFC 8460: neither appears in its Updates list, and its info page records no such relationship. The only effect on the tool is that the server accepts the underscore labels in both lookup names.

Each finding the checker can emit, grouped by the part of the setup it judges, with what it means for mail sent to the domain. The RFC section column links the rule behind each finding; “none” marks a Tamperbox recommendation that the specification does not set.

The TXT record that tells senders a policy exists and which version to fetch.

Finding Severity What it means for mail Fix RFC section
No record at _mta-sts.domain FAIL Senders never look for a policy Publish v=STSv1; id=… RFC 8461 3.1
Publish exactly one MTA-STS record. FAIL Senders cannot pick one Keep one record RFC 8461 3.1
The version tag must be first., An MTA-STS record starts with v=STSv1., id= must be 1 to 32 letters or digits. FAIL Senders ignore the record Correct the record RFC 8461 3.1
id=X (pasted record) PASS The record is valid Change the id when the file changes RFC 8461 3.1

The file at https://mta-sts.<domain>/.well-known/mta-sts.txt, line by line.

Finding Severity What it means for mail Fix RFC section
No policy file FAIL Senders treat the domain as having no policy Serve the file at the well-known URL over HTTPS as text/plain RFC 8461 3.3
version: STSv1 is missing FAIL Senders discard the policy Add the line RFC 8461 3.2
mode: X (invalid) FAIL Senders discard the policy Use enforce, testing or none RFC 8461 3.2
mode: testing CHECK Failures are reported but mail still delivers over plain text Switch to enforce when reports are clean RFC 8461 5
mode: enforce PASS Senders require TLS to a listed server RFC 8461 5
No mx: lines FAIL No server would be allowed Add one mx line per host RFC 8461 3.2
Invalid MX pattern X FAIL Senders discard the policy Fix the line RFC 8461 3.2
max_age is missing or out of range FAIL Senders discard the policy Use seconds up to one year RFC 8461 3.2
max_age N s CHECK Protection lapses quickly Use a week or more none (Tamperbox recommendation)
Not a key: value line: X FAIL Senders may discard the policy Fix the line RFC 8461 3.2

Whether every mail server the domain publishes is allowed by the policy.

Finding Severity What it means for mail Fix RFC section
X is not in the policy FAIL (enforce) or CHECK Senders refuse that server, or will once enforced Add mx: X RFC 8461 4.1, 5
MX coverage not established FAIL No usable MX servers Publish MX records RFC 5321 5.1, RFC 7505 3

The _smtp._tls record that asks senders for daily failure reports.

Finding Severity What it means for mail Fix RFC section
No TLS-RPT record CHECK You will not hear about failed connections Publish v=TLSRPTv1; rua=mailto:… RFC 8460 3; CHECK is Tamperbox’s severity
Invalid report address X FAIL Senders skip the address Use mailto: or https: RFC 8460 3
TLS reports on PASS Daily reports go to the listed addresses RFC 8460 3, 4.1
  1. Publish a TLS-RPT record first: _smtp._tls.<domain> TXT "v=TLSRPTv1; rua=mailto:tls-reports@<domain>", so you hear about problems from day one.
  2. Create the host mta-sts.<domain> and serve /.well-known/mta-sts.txt over HTTPS with a certificate valid for that host, as text/plain, with no redirect. Start with mode: testing, one mx: line per MX host, and max_age: 604800.
  3. Publish _mta-sts.<domain> TXT "v=STSv1; id=<date>01".
  4. Check the domain here: every step in the chain should pass, with “mode: testing” as the only CHECK.
  5. After a week of clean TLS reports, change the mode to enforce, change the id, and check again.

The chain names the reason. The usual causes: the mta-sts host does not exist; the web server redirects every path to www; a static host serves .txt as application/octet-stream; the certificate does not cover the mta-sts host. Fix the one named, then check again.

Add mx: <host> to the file; the suggested policy already includes every uncovered host. Change the id in the record so senders fetch the new file. When a wildcard covers a provider’s servers, remember it covers one label only.

Read the TLS reports until they show no failures for every MX host, then change mode: testing to mode: enforce and the id. The suggested policy on the page is that file.

Use a week or more once the policy is stable; Heal it sets 604800 on a pasted file. Values above one year are invalid.

Publish mode: none with a new id and wait for the longest max_age you ever published before removing the record and the file.

Each case is built from the policy you pasted or the domain serves.

Case What it does to the file Heal it offers (pasted file)
Missing version line Removes version: Add version: STSv1
No mx lines Removes every mx: line Nothing: add the lines yourself
Unknown mode Misspells the mode (enforced, test, off) Change mode to enforce or testing
max_age too short Sets max_age: 300 Set max_age to one week
max_age too long Sets max_age: 99999999 Set max_age to one week

The page opens on a live check of tamperbox.dev. Its published records and findings can change over time.

For the deterministic walkthrough below, enter harbor-supply.example. This reserved .example domain is answered from synthetic data in your browser; it sends no live lookup. Its record announces a policy (v=STSv1; id=20261001T0000), the file is in testing mode with mx: mx1.inboxcloud.example, mx: *.mx.inboxcloud.example and max_age: 86400, the MX records name mx1.inboxcloud.example, alt1.mx.inboxcloud.example and backup.harbor-supply.example, and TLS-RPT reports go to tls-reports@harbor-supply.example.

Testing only: senders report failures but still deliver over plain text. Two of three MX servers are covered; the backup is not and would be refused once the policy enforces. The suggested policy adds mx: backup.harbor-supply.example, switches to enforce and raises max_age to a week. Replace the sample with your own domain and every section, card and link is rewritten for it.

The Tamperbox MCP server runs the same checks. Search its catalog for the MTA-STS operation, inspect the input schema, and call it with the domain. Keep the warning block with any conclusion:

  • No connection is made to any mail server; STARTTLS and MX certificates are not tested.
  • Senders cache a policy for max_age seconds; a change takes effect slowly, and a cached policy may still apply to a domain whose record has gone.
  • A wildcard mx line covers exactly one label.

See Connect an MCP client and Code mode for the calling pattern, and Security and privacy for where the domain travels.

  • DNS and HTTPS only; no SMTP connection.
  • One fetch of one URL, without following redirects.
  • A pasted file is checked for syntax; coverage and publication need the domain.
  • One DNS answer, from one public resolver, at one moment.
  • Nothing is stored.