# 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.

Source: emailmarketing.net — https://emailmarketing.net/learn/transport-security/tls-rpt

If you are about to enforce TLS for mail sent to your domain, you need to know first whether any legitimate mail would fail. TLS reporting (TLS-RPT) tells you. Your domain publishes a DNS record that asks sending mail servers (MTAs) to report every day how TLS negotiation with your domain went: what succeeded, what failed, and why.

TLS-RPT is defined in RFC 8460 and works alongside [MTA-STS](https://emailmarketing.net/learn/transport-security/mta-sts) and [DANE](https://emailmarketing.net/learn/transport-security/dane-smtp). Those two mechanisms enforce TLS; TLS-RPT tells you whether enforcement would break real mail flow, or is already breaking it. It does for transport security what DMARC aggregate reports do for [authentication](https://emailmarketing.net/learn/authentication/dmarc).

## The DNS record

The record is 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 | A comma-separated list of report destinations, using the `mailto:` or `https:` scheme |

Several `rua` endpoints are allowed. A reporter may try all of them or choose one, and the report counts as delivered as soon as **any one** endpoint accepts it.

## Report generation and timing

- **Period:** one full calendar day in UTC (00:00–24:00 UTC).
- **Delivery delay:** reporters should add a random delay of 1–14,400 seconds, so that receivers are not hit by all reports at once.
- **Retries:** if delivery fails, retry for up to 24 hours after the first attempt, preferably with exponential backoff.
- **Exception for email reports:** when a report is delivered by email, the reporter must NOT apply MTA-STS or DANE failures to that delivery. Reports about broken TLS must still get through, without encryption if necessary.

## Delivery mechanisms

### By email (`mailto:`)

| Aspect | Requirement |
|---|---|
| MIME structure | `multipart/report; report-type="tlsrpt"` |
| Media type of the report part | `application/tlsrpt+json` (plain) or `application/tlsrpt+gzip` (compressed with gzip, with the extension `.json.gz`; gzip is recommended) |
| Required headers | `TLS-Report-Domain:` (the domain the report is about) and `TLS-Report-Submitter:` (the reporting domain) |
| DKIM | Report messages MUST carry a valid DKIM signature with the service type `s=tlsrpt`, and the `l=` (body length) tag MUST NOT be used. Receivers should ignore email reports that are not signed |
| Subject | `Report Domain: <policy-domain> Submitter: <sender-domain> Report-ID: <unique-id@domain>` |

### By HTTPS (`https:`)

- An HTTP POST of `application/tlsrpt+json` or `application/tlsrpt+gzip` to the endpoint.
- Delivery succeeds when the response is HTTP 200 or 201.
- Reporters MAY ignore HTTPS certificate validation errors when they post, because the reporting 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 fields:

| Field | Meaning |
|---|---|
| `organization-name` | The reporting organization |
| `date-range` | `start-datetime` / `end-datetime`, in RFC 3339 format, covering the UTC day |
| `contact-info` | Email address of the party responsible for the report |
| `report-id` | Unique report identifier |
| `policies` | An array of result objects, one for each policy (it is 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 entry and a DANE entry for the same domain:

```json
{
  "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 contains:

| Field | Meaning |
|---|---|
| `result-type` | The type of failure (table below) |
| `sending-mta-ip` | The reporter's sending IP address (IPv4 in dotted-decimal notation, or IPv6 as in RFC 5952) |
| `receiving-mx-hostname` | The MX hostname the sender connected to |
| `receiving-mx-helo` | Optional: the HELO or EHLO banner the sender saw |
| `receiving-ip` | The destination IP address used |
| `failed-session-count` | The number of sessions with this failure |
| `additional-information` | Optional: a URI with more detail |
| `failure-reason-code` | Optional: detail about the TLS error (for example, an X.509 or OpenSSL error string) |

A single session can count toward more than one `result-type`, because the types do not exclude each other.

## Failure result types

| result-type | Class | Meaning |
|---|---|---|
| `starttls-not-supported` | negotiation | The recipient's MX did not advertise STARTTLS |
| `certificate-host-mismatch` | negotiation | The identity in the certificate (hostname or SAN) did not match |
| `certificate-expired` | negotiation | The certificate is past the end of its validity period |
| `certificate-not-trusted` | negotiation | An untrusted or unknown certificate authority, a violated name constraint, or an error in the chain |
| `validation-failure` | general | A negotiation failure that fits no other type; see `failure-reason-code` for detail |
| `tlsa-invalid` | DANE | An error validating the TLSA record; no valid member of the record set matched |
| `dnssec-invalid` | DANE | DNSSEC validation failed; no validly signed records were returned |
| `dane-required` | DANE | The sender requires DANE, but no valid TLSA records signed with DNSSEC exist |
| `sts-policy-fetch-error` | MTA-STS | The policy could not be retrieved (for example, the policy host was unreachable) |
| `sts-policy-invalid` | MTA-STS | The MTA-STS policy was retrieved but failed validation |
| `sts-webpki-invalid` | MTA-STS | The MTA-STS policy host failed Web PKI (certificate) authentication |

## Using the reports

TLS-RPT is how you reduce the risk of moving [MTA-STS](https://emailmarketing.net/learn/transport-security/mta-sts) from `testing` to `enforce`:

1. **Publish TLS-RPT first**, or at the same time as an MTA-STS policy in `testing` mode. Reports arrive from every major sender that implements RFC 8460: Google, Microsoft and other large platforms send them.
2. **Watch `total-failure-session-count` for each policy type.** MTA-STS failures in testing mode that are not zero represent mail that would have been deferred or lost under enforcement.
3. **Sort failures by result type:**
   - `certificate-*`: fix the certificates on the named `receiving-mx-hostname` (expired, wrong SAN, private certificate authority).
   - `starttls-not-supported`: an MX, often a backup MX or an old appliance, has TLS turned off.
   - `sts-policy-fetch-error` / `sts-webpki-invalid`: your HTTPS endpoint at `mta-sts.<domain>`, or its certificate, is broken.
   - `sts-policy-invalid`: the policy syntax is wrong, or an `mx` pattern does not cover a real MX.
   - `tlsa-*` / `dnssec-invalid`: TLSA records are out of date, or DNSSEC signing has a problem (see the [DANE guidance on key rotation](https://emailmarketing.net/learn/transport-security/dane-smtp)).
4. **Keep monitoring after you enforce.** An expired certificate on one MX now defers mail from strict senders without any other warning, and TLS-RPT is often the only signal from outside your systems.
5. If one organization reports failures for a long time while others report success, the cause is usually a problem on the network path of that sender (or interception), not your configuration.

A note on internationalized domain names: they appear as Punycode A-labels in all records and reports, never as U-labels.
