SMTP TLS Reporting (TLS-RPT, RFC 8460)
The reporting channel for SMTP transport security — DNS record syntax, JSON report schema, the full failure result-type taxonomy, and how to use the reports operationally.
TLS-RPT (RFC 8460) is the feedback loop for SMTP transport security. A domain publishes a DNS record asking sending MTAs to report, daily, how TLS negotiation to that domain went — successes, failures, and why. It is the companion to MTA-STS and DANE: those mechanisms enforce TLS; TLS-RPT tells you whether enforcement would break (or is breaking) real mail flow. It plays the same role for transport security that DMARC aggregate reports play for authentication.
The DNS record
A TXT record at _smtp._tls.<policy-domain>:
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:reports@example.com"
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=https://reporting.example.com/v1/tlsrpt"
| Directive | Required | Value |
|---|---|---|
v |
yes | TLSRPTv1 |
rua |
yes | Comma-separated list of report destinations; schemes: mailto: or https: |
Multiple rua endpoints are allowed; a reporter may try all or pick one, and the report counts as delivered once any single endpoint accepts it.
Report generation and timing
- Period: one full UTC calendar day (00:00–24:00 UTC).
- Delivery delay: reporters should add a random delay of 1–14,400 seconds to avoid thundering-herd load on receivers.
- Retries: on failure, retry for up to 24 hours after the initial attempt (exponential backoff preferred).
- Escape hatch: when a report is delivered by email, the reporter must NOT honor MTA-STS or DANE failures for that delivery — reports about broken TLS must still get through, unencrypted if necessary.
Delivery mechanisms
Via email (mailto:)
| Aspect | Requirement |
|---|---|
| MIME structure | multipart/report; report-type="tlsrpt" |
| Report part media type | application/tlsrpt+json (plain) or application/tlsrpt+gzip (gzip'd; extension .json.gz; gzip recommended) |
| Required headers | TLS-Report-Domain: (domain reported on), TLS-Report-Submitter: (reporting domain) |
| DKIM | Report messages MUST carry a valid DKIM signature with service type s=tlsrpt; the l= (body length) tag MUST NOT be used. Receivers should ignore unsigned email reports |
| Subject | Report Domain: <policy-domain> Submitter: <sender-domain> Report-ID: <unique-id@domain> |
Via HTTPS (https:)
- HTTP POST of
application/tlsrpt+jsonorapplication/tlsrpt+gzipto the endpoint. - Success = HTTP 200/201.
- Reporters MAY ignore HTTPS certificate validation errors when posting (the report channel must not be blocked by the very problems it reports).
Report filename convention
{sender}!{policy-domain}!{start-timestamp}!{end-timestamp}[!{unique-id}].{json|json.gz}
Example: mail.sender.example.com!example.net!1470013207!1470186007!001.json.gz
Report content (JSON schema)
Top level:
| Field | Meaning |
|---|---|
organization-name |
Reporting organization |
date-range |
start-datetime / end-datetime, RFC 3339, covering the UTC day |
contact-info |
Email address of the party responsible for the report |
report-id |
Unique report identifier |
policies |
Array of per-policy result objects (an array even when there is only one policy) |
Each entry in policies describes one policy the sender evaluated (a single day can include both an MTA-STS and a DANE entry for the same domain):
{
"policy": {
"policy-type": "sts" | "tlsa" | "no-policy-found",
"policy-string": ["version: STSv1", "mode: testing", "..."],
"policy-domain": "example.com",
"mx-host": "*.mail.example.com"
},
"summary": {
"total-successful-session-count": 5326,
"total-failure-session-count": 303
},
"failure-details": [ ... ]
}
Each failure-details entry:
| Field | Meaning |
|---|---|
result-type |
Failure classification (table below) |
sending-mta-ip |
Reporter's sending IP (IPv4 dotted-decimal / IPv6 per RFC 5952) |
receiving-mx-hostname |
MX hostname the sender connected to |
receiving-mx-helo |
Optional: HELO/EHLO banner observed |
receiving-ip |
Destination IP used |
failed-session-count |
Number of sessions matching this failure |
additional-information |
Optional URI with supplementary detail |
failure-reason-code |
Optional TLS error detail (e.g., an X.509/OpenSSL error string) |
A single session can contribute to more than one result-type bucket — the types are not mutually exclusive.
Failure result-types
| result-type | Class | Meaning |
|---|---|---|
starttls-not-supported |
negotiation | Recipient MX did not advertise STARTTLS |
certificate-host-mismatch |
negotiation | Certificate identity (hostname/SAN) didn't match |
certificate-expired |
negotiation | Certificate past its validity end date |
certificate-not-trusted |
negotiation | Untrusted/unknown CA, name-constraint violation, or chain error |
validation-failure |
general | Unclassified negotiation failure; see failure-reason-code for detail |
tlsa-invalid |
DANE | TLSA record validation error; no valid RRset member matched |
dnssec-invalid |
DANE | DNSSEC validation failed; no validly signed records returned |
dane-required |
DANE | Sender requires DANE but no valid DNSSEC-signed TLSA records exist |
sts-policy-fetch-error |
MTA-STS | Policy could not be retrieved (e.g., policy host unreachable) |
sts-policy-invalid |
MTA-STS | Fetched MTA-STS policy failed validation |
sts-webpki-invalid |
MTA-STS | MTA-STS policy host failed Web PKI (certificate) authentication |
Using the reports
TLS-RPT is how you de-risk moving MTA-STS from testing to enforce:
- Publish TLS-RPT first (or together with a
testing-mode MTA-STS policy). Reports arrive from every major sender that implements RFC 8460 — Google, Microsoft, and other large platforms report. - Watch
total-failure-session-countper policy-type. Nonzero MTA-STS failures in testing mode = mail that would have been deferred/lost under enforce. - Triage by result-type:
certificate-*→ fix certs on the namedreceiving-mx-hostname(expired, wrong SAN, private CA).starttls-not-supported→ an MX (often a backup MX or a legacy appliance) with TLS off.sts-policy-fetch-error/sts-webpki-invalid→ yourmta-sts.<domain>HTTPS endpoint or its certificate is broken.sts-policy-invalid→ policy syntax or anmxpattern that doesn't cover a real MX.tlsa-*/dnssec-invalid→ stale TLSA records or a DNSSEC signing problem (see DANE key-rotation guidance).
- After enforcing, keep monitoring. A cert expiry on one MX now silently defers mail from strict senders; TLS-RPT is often the only external signal.
- Sustained failures reported from a single organization while others report success usually indicate a path problem (or interception) specific to that sender's network rather than your configuration.
IDN note: internationalized domain names appear as Punycode A-labels throughout records and reports, never U-labels.