emailverifier.dev
Posts

MTA-STS and TLS-RPT: Enforce and Monitor Email TLS

| 7 min read | Usama Ejaz
DNS discovery, an HTTPS policy, enforced SMTP TLS, and aggregate reporting linked in one loop

MTA-STS lets a receiving domain tell supporting senders which MX hosts are authorized and that delivery must use authenticated TLS. TLS-RPT tells the domain what those senders saw when policy validation succeeded or failed. Deploy them together: MTA-STS without reports can fail quietly, while TLS-RPT without a transport policy can observe problems but cannot require secure delivery.

The important word is supporting. These standards do not make every sender on the internet comply, and they do not encrypt a stored message or authenticate the person who wrote it. They harden the server-to-server hop for MTAs that implement the policy.

I think about this as three separate control planes: discovery in DNS, enforcement instructions over HTTPS, and aggregate evidence through TLS-RPT. Mixing those jobs is how a harmless policy edit becomes delayed mail.

The three control planes

STARTTLS upgrades an SMTP connection, but ordinary opportunistic TLS can continue when authentication or privacy is insufficient. RFC 8461 was designed to make downgrade-resistant behavior publishable for receiving domains.

Plane Location Job Common failure
Discovery _mta-sts.example.com Announce MTA-STS and signal a policy revision The TXT id changes before the HTTPS body is ready
Policy https://mta-sts.example.com/.well-known/mta-sts.txt List allowed MX patterns, mode, and cache lifetime An MX hostname or certificate does not match the policy
Evidence _smtp._tls.example.com Publish where aggregate TLS reports should go Reports arrive but nobody groups and investigates them

The records below use example.com as a hypothetical domain. Replace every hostname and mailbox with values you operate.

1. DNS announces the MTA-STS version

_mta-sts.example.com. 3600 IN TXT "v=STSv1; id=20260918-01"

The id is not a timestamp parser or a policy checksum. It is an opaque revision identifier. A sender compares it with the identifier attached to its cached policy and fetches again when the value changes. RFC 8461 section 3.1 requires each policy instance to have a unique identifier, with no ordering implied.

That gives you a strict update order: publish and verify the new HTTPS body first, then change the TXT id. Reversing the order can make a sender see a new identifier and fetch the old body.

2. HTTPS carries the policy that senders cache

version: STSv1
mode: testing
mx: mx1.example.net
mx: *.backup.example.net
max_age: 86400

The policy must be served at the fixed HTTPS path with a certificate valid for mta-sts.example.com. A successful fetch is an HTTP 200 response. Redirects are not followed. The mx values match the hostnames returned by your domain's MX records, not the visible From domain and not an IP address.

Wildcard matching is deliberately narrow. *.backup.example.net matches mx2.backup.example.net, but not backup.example.net or west.mx2.backup.example.net. The policy needs one mx: line for every allowed pattern. If you have not mapped those names against every production and backup route, stop at testing.

The max_age is seconds from the last successful fetch. I start with a short value during rollout, then lengthen it after the report stream is quiet. A long cache improves resilience against discovery attacks, but it also lengthens the tail of a bad policy. This trade-off is operational, not cosmetic.

3. TLS-RPT returns aggregate evidence

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

RFC 8460 also permits an HTTPS report endpoint. The reports normally cover a full UTC day and contain success and failure counts plus grouped failure details. They are not an immediate alert for one recipient address.

The failure labels are the useful part. starttls-not-supported, certificate-host-mismatch, certificate-expired, and certificate-not-trusted point to the SMTP/TLS path. sts-policy-fetch-error, sts-policy-invalid, and sts-webpki-invalid point to the policy host. A generic validation-failure needs its reason code and surrounding evidence before you decide what broke.

Follow one delivery through the policy

Suppose a sender has mail for person@example.com. A conforming implementation follows a sequence like this:

  1. Look for a non-expired cached policy. If there is none, discover the TXT record and fetch the HTTPS policy.
  2. Resolve the recipient domain's MX records and traverse candidates by normal MX preference. MTA-STS does not redefine MX priority. The MX priority guide covers that selection separately.
  3. Check whether the selected MX hostname matches an allowed mx: pattern.
  4. Require STARTTLS and validate that the server certificate is current, trusted, and valid for the MX hostname.
  5. In testing mode, report a policy failure but permit delivery as though the failure had not occurred. In enforce mode, do not deliver to that failing host. Try the next candidate if one exists.
  6. If no candidate can accept policy-compliant delivery, treat the problem as transient and retry. Before a permanent failure, check whether the TXT id signals an updated policy.

This is why an MTA-STS failure is not evidence that the mailbox is invalid. It is transport-policy evidence about the route to the domain. The distinction is the same one I use in validation, verification, and confirmation: each layer answers a different question.

Roll out with a cache-aware state machine

A safe rollout is a sequence of states, not one DNS change.

  1. Inventory. Resolve every current MX, including backup routes. Confirm STARTTLS, the certificate chain, expiry, and hostname coverage on each host.
  2. Observe. Publish TLS-RPT first. Establish that reports are arriving and that someone owns the mailbox or HTTPS ingestion path.
  3. Test. Serve the MTA-STS policy with mode: testing and a short max_age. Update the policy body before changing the TXT id.
  4. Reconcile. Group failures by result type, receiving MX, sending organization, and time range. Fix persistent host or certificate failures. A few reports from one sender are not enough to prove a global outage.
  5. Enforce. Change the policy to mode: enforce, publish a new id, and watch both reports and queue delays. Increase max_age only after the route is stable.

For a normal policy update, keep the old and new routes working through the DNS TTL and prior policy cache window. RFC 8461's update guidance explicitly warns that senders may continue using an older cached policy until the TXT update is visible.

For a complete rollback, do not simply delete the TXT record and policy host. A sender may still hold the old enforce policy. Publish mode: none with a short max_age, change the TXT id, wait for every previously served policy window to expire, and only then remove the endpoints.

The strongest objection: isn't STARTTLS already enough?

STARTTLS is valuable. It encrypts a large share of server-to-server mail without requiring every domain to prearrange a policy. But that compatibility is also the downgrade surface: a network attacker can suppress the STARTTLS advertisement or redirect the route, and ordinary opportunistic delivery may continue.

MTA-STS gives supporting senders a prior expectation: use one of these MX hosts, negotiate TLS, and validate the certificate. TLS-RPT gives you evidence about where that expectation failed. Neither replaces SPF, DKIM, or DMARC, which deal with sender authorization and message identity. The SPF, DKIM, and DMARC guide owns that boundary.

There is another fair objection: enforcement can delay legitimate mail when your own policy is wrong. Correct. That is why the operational design matters as much as the record syntax. Testing mode, aggregate reports, short initial caches, explicit ownership, and a rehearsed none rollback are the safety system.

The operational contract

  • DNS announces a revision. HTTPS defines the policy. TLS-RPT reports what participating senders observed.
  • Every production and backup MX must match the policy and present a valid certificate before enforcement.
  • The policy body changes before the TXT id.
  • testing gathers evidence; enforce can defer mail.
  • A cached policy survives removal of the discovery record, so rollback uses mode: none and time.
  • TLS policy failure is not a mailbox verdict, and transport encryption is not sender authentication.

If I had to reduce the deployment to one rule, it would be this: make the report path work before the policy can block a delivery path.

Continue reading