---
title: "TLS-RPT Reports: SMTP TLS Reporting Explained (RFC 8460)"
description: "TLS-RPT reports tell you when SMTP TLS fails between mail servers. See an annotated RFC 8460 JSON example, every result type, and how to set it up."
publishedAt: 2026-05-08
tags: ["tls-rpt", "mta-sts", "dane", "email-authentication", "rfc-8460"]
faq:
  - question: "What is a TLS-RPT report?"
    answer: "A TLS-RPT report is a once-per-UTC-day JSON aggregate that a sending mail server emails to a recipient domain, summarising every SMTP TLS session attempted that day. Defined in RFC 8460, it lists successes, failures, the MTA-STS or DANE policy applied, and an IANA result type for each fault."
  - question: "How do I check my TLS-RPT record?"
    answer: "Run `dig +short TXT _smtp._tls.<your-domain>` to see the published policy. For deeper validation, paste the domain into DMARCguard's TLS-RPT checker — it parses the TXT syntax, walks every `rua=` URI, and confirms the reporting mailbox is reachable so senders won't silently drop reports."
  - question: "How is a TLS-RPT report delivered?"
    answer: "Reports are gzipped JSON delivered over `mailto:` (DKIM-signed, content type `application/tlsrpt+gzip`) or HTTPS POST. RFC 8460 §3 requires delivery even when TLS to the report mailbox fails — so reports may arrive in cleartext when the very condition they describe blocks encryption."
  - question: "Do I need TLS-RPT if I already have MTA-STS or DANE?"
    answer: "Yes. TLS-RPT is the only feedback channel for an MTA-STS policy in `mode: testing` and the only way to know a DANE rollover hasn't broken inbound mail. Without it, an enforce-mode policy can silently bounce real mail — exactly what happened to a Mail-in-a-Box operator with Outlook in October 2020."
  - question: "Why am I not getting Microsoft TLS-RPT reports?"
    answer: "Two known causes. Microsoft delivers reports to only the FIRST `rua=` URI in your TXT record, so a third-party aggregator listed second receives nothing. Microsoft also requires at least two messages per 24-hour UTC window before generating any report at all (URIports, August 2024)."
  - question: "What does sts-policy-fetch-error mean in a TLS-RPT report?"
    answer: "The sender saw a valid `_mta-sts` TXT record but couldn't fetch `https://mta-sts.<domain>/.well-known/mta-sts.txt` — a TCP timeout, a 4xx/5xx response, or a forbidden redirect. Fix it by serving plain text with no redirects, then bump the policy `id=` so caching senders re-fetch."
  - question: "How often are TLS-RPT reports sent?"
    answer: "Once per UTC day per sender, recipient, and policy tuple, per RFC 8460 §4.1, with up to four hours of randomised delay. Postfix 3.10's reporter documents an additional ~12-hour processing lag, so a report covering Monday usually arrives mid-Tuesday."
---
# TLS-RPT Reports: How SMTP TLS Reporting Works (RFC 8460, with JSON example)

SMTP STARTTLS is opportunistic. When a TLS handshake fails or downgrades to
plaintext between two mail servers, the sending side sees the bounce and the
receiving side sees nothing. A TLS-RPT report (RFC 8460) is the only standard
channel that flips that asymmetry: senders email you a daily JSON aggregate of
every TLS session attempted against your MX hosts and tell you exactly which
ones broke.

That visibility matters because the policies that _enforce_ TLS are still
rare. Across DMARCguard's February 2026 scan of 5.5 million domains, only 0.3%
publish an MTA-STS policy and 0.0% publish a DANE TLSA record. URIports'
January 2026 Top 1M survey caps MTA-STS at 0.7% globally — and because TLS-RPT
is almost always deployed alongside MTA-STS, that 0.7% is the practical
ceiling for TLS-RPT adoption too. (DMARCguard's scanner doesn't yet record
`_smtp._tls` TXT presence directly; we cite URIports' Top 1M survey
(~0.7%) as the closest public proxy.) The few operators who _do_ enforce
policies depend on TLS-RPT to know when their policy is breaking real mail.
Read the [TLS-RPT protocol fundamentals](/learn/tls-rpt/) for the full primer,
or keep going for the things every other guide skips.

This post walks through a real annotated JSON dump, the eleven IANA result
types each paired with a fix, the deployment order operators actually back,
and provider-specific setup for Google Workspace, Microsoft 365, Postfix, and
Exim.

## What is a TLS-RPT report?

A TLS-RPT report is a once-per-UTC-day JSON aggregate that a sending MTA emails
(or HTTPS-POSTs) to a recipient domain. It summarises how many SMTP sessions
opened — or failed to open — TLS against that domain's MX hosts and records
which MTA-STS or DANE policy was applied to each one. The reporting cadence
and shape are fixed: per [RFC 8460 §4.1](https://datatracker.ietf.org/doc/html/rfc8460#section-4.1),
one report per (sender, recipient, policy) tuple per UTC day, with up to four
hours of randomised delay.

The protocol was standardised in September 2018 by authors at Yahoo, Google,
and Comcast as the visibility companion to MTA-STS (RFC 8461) and
DANE-for-SMTP (RFC 7672). MTA-STS and DANE tell senders to _enforce_ TLS;
TLS-RPT tells you when that enforcement broke something.

Every report contains the same top-level shape:

- `organization-name` — who sent the report (e.g. Google Inc., Microsoft
  Corporation).
- `date-range` — the 24-hour window covered, in RFC 3339 timestamps.
- `contact-info` — an addr-spec mailbox a human can reply to.
- `report-id` — a sender-defined unique identifier.
- `policies[]` — an array of `{policy, summary, failure-details[]}` objects,
  one per evaluated policy. The RFC mandates an array even for a single
  policy.

Confirmed senders today are Google, Microsoft, Comcast, Mail.ru, and Mimecast
(URIports, August 2024). Yahoo and Apple are claimed by some vendor blogs but
unconfirmed by any public JSON dump as of April 2026 — assume they may emit
reports, but don't depend on it.

<Figure
  src="/images/blog/tls-rpt-report/tls-rpt-report_lifecycle_flowchart.svg"
  alt="TLS-RPT report lifecycle flowchart showing five stages from STARTTLS attempt at the sender MTA, outcome recording with applied MTA-STS or DANE policy, daily JSON aggregation, gzip plus DKIM dispatch via mailto: rua URI or HTTPS POST, and recipient mailbox ingestion at _smtp._tls.<domain>"
  caption="Once-per-UTC-day cadence per (sender, recipient, policy) tuple — with up to four hours of randomised delay and an additional ~12-hour processing lag for Postfix 3.10."
/>

## An annotated TLS-RPT JSON report (RFC 8460 §4)

The single most useful thing a TLS-RPT guide can do is paste a real report and
walk every field. This one is a Google → krvtz.net aggregate adapted from
Paweł Krawczyk's `tlsrpt-rs` fixtures, with the recipient domain sanitised to
`example.com` and a `validation-failure` block grafted in from a separate
Google → acme.com sample so both the heartbeat and failure paths are
exercised.

<CodeBlock
  filename="tls-rpt-sample.json"
  lang="json"
  code={sampleReport}
/>

Block-by-block, here's what each field means in the wild — and where vendors
diverge from the spec.

**`organization-name`** is a required string. Google still emits
`"Google Inc."` even though the legal entity has been Google LLC since 2017.
Microsoft emits `"Microsoft Corporation"`. Mail.ru emits the bare `"Mail.ru"`.
Reference parsers (parsedmarc, mox, tlsrpt-rs) all reject reports lacking this
field.

**`date-range.start-datetime` / `end-datetime`** are RFC 3339 strings. There's
a quiet bug here: Google and Microsoft emit `T00:00:00Z` → `T23:59:59Z`, while
Mail.ru emits `T00:00:00Z` → next-day `T00:00:00Z`. Computed report duration
differs by one second across senders, and no parser normalises it.

**`contact-info`** is an addr-spec — Google uses
`smtp-tls-reporting@google.com`, Microsoft uses `tlsrpt-noreply@microsoft.com`.
Per [RFC 8460 §5.6](https://datatracker.ietf.org/doc/html/rfc8460#section-5.6),
this value is allowed to differ from the SMTP envelope-from of the report
email itself. Don't assume they match.

**`report-id`** has three real formats coexisting in production:

| Format                       | Sender    | Example                                        |
| ---------------------------- | --------- | ---------------------------------------------- |
| `<ISO-8601>_<policy-domain>` | Google    | `2024-09-18T00:00:00Z_krvtz.net`               |
| `<FILETIME>+<policy-domain>` | Microsoft | `133765181884122747+krvtz.net`                 |
| `<UUID>@<reporter-domain>`   | Mail.ru   | `c96d67df-0440-57f7-6e96-c83824d0fdf2@mail.ru` |

A parser that assumes a single regex will quietly drop two-thirds of senders.

**`policies[]`** is required to be an array, even for a single policy.
Multi-policy reports — one entry for MTA-STS, one for DANE TLSA — are
documented in the RFC and demonstrably emitted by Postfix 3.10+ to BSI
TR-03108 recipients, but no public capture of one exists as of April 2026.

Inside each policy:

- **`policy.policy-type`** is an enum: `sts`, `tlsa`, or `no-policy-found`.
  The latter is what you see when only `_smtp._tls` is published with no
  MTA-STS — Google heartbeats from low-MTA-STS recipients carry it.
- **`policy.policy-string[]`** is required to be an array of strings.
  Mailhardener's KB shows a scalar form (`"version: STSv1 mode: enforce …"`)
  which violates the schema; parsedmarc silently drops scalar values.
- **`policy.policy-domain`** is your domain, verbatim, no trailing dot.
- **`summary.total-successful-session-count`** is the daily heartbeat counter.
  Microsoft requires at least two messages per UTC 24-hour window before
  generating any report at all — low-volume domains see Microsoft as a
  non-emitter.
- **`summary.total-failure-session-count`** is the daily failure counter. No
  parser checks that this matches the sum of `failed-session-count` across
  `failure-details[]`, so vendor inconsistencies pass through silently.
- **`failure-details[]`** is omitted entirely on clean days. When present,
  each entry carries a `result-type` (the IANA enum we'll dissect in the next
  section), a `sending-mta-ip`, an optional `receiving-mx-hostname` and
  `receiving-ip`, a required `failed-session-count`, and an optional
  `failure-reason-code`.

There's one last footgun worth flagging. The RFC 8460 prose calls a field
`additional-info-uri`; the schema example in §4.4 spells it
`additional-information`. mox follows the schema spelling, parsedmarc follows
the prose spelling, and parsedmarc silently drops the schema-spelled key.
DMARCguard's parser handles both. If your aggregator only reads one, you're
losing data — quietly.

A clean Google heartbeat and a Microsoft `sts-policy-fetch-error` report look
very different on the wire. The diff is worth seeing side-by-side:

<Figure
  src="/images/blog/tls-rpt-report/tls-rpt-report_success-vs-failure_comparison.svg"
  alt="Side-by-side comparison of a clean Google heartbeat TLS-RPT report with total-successful-session-count 50 and no failure-details array, against a Microsoft sts-policy-fetch-error report with total-failure-session-count 2 and a failure-details entry containing only result-type and failed-session-count"
  caption="Microsoft omits policy-string, sending-mta-ip, MX hostname, and failure-reason-code on policy-fetch errors — the fields a recipient most needs for diagnosis are exactly the ones that don't ship."
/>

Want this annotation rendered automatically against your own report? Paste a
sample into [DMARCguard's TLS Report Analyzer](/tools/tls-report-analyzer/) and
every field is labelled inline.

## Every TLS-RPT result type and how to fix it

The IANA "STARTTLS Validation Result Types" registry has held exactly **eleven
values since 2018-09-28** — frozen, despite
[RFC 8460 §4.3](https://datatracker.ietf.org/doc/html/rfc8460#section-4.3)
explicitly anticipating growth. Recovering signal from a TLS-RPT report means
knowing which fault each value points at and what to change. The registry
itself is the canonical source:
[IANA STARTTLS Validation Result Types](https://www.iana.org/assignments/starttls-validation-result-types/starttls-validation-result-types.xhtml).

Every cell below uses the verbatim hyphenated string so you can grep your own
reports.

| `result-type`               | What it means                                                              | Most likely cause                                              | Sender or receiver fix                                                                                                                              |
| --------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `starttls-not-supported`    | Receiver MX answered EHLO but didn't advertise STARTTLS, or returned 5xx.  | TLS not configured; middlebox stripping the 250-STARTTLS line. | Postfix: `smtpd_tls_security_level = may` + `smtpd_tls_chain_files`. Exim: `tls_advertise_hosts = *` + `tls_certificate`. Disable SMTP fixup on ASA. |
| `certificate-host-mismatch` | Cert SAN/CN doesn't cover the MX hostname.                                 | Web cert installed on the MX, or shared-IP cert.               | Re-issue with every MX FQDN in SAN. For Exim multi-MX with SNI, use `tls_certificate = ${if eq{$tls_in_sni}{...}{...}}`.                            |
| `certificate-expired`       | Server presented a cert past its `notAfter`.                               | Renewal automation broken or didn't reload the MTA.            | `certbot renew --deploy-hook 'systemctl reload postfix'`. Postfix caches `smtpd_tls_chain_files` at startup — reload is required.                   |
| `certificate-not-trusted`   | Sender couldn't build a chain to a trusted root.                           | Leaf-only cert served; missing intermediate; CA not in trust.  | Serve full chain via `smtpd_tls_chain_files = .../privkey-fullchain.pem`. Exim: point `tls_certificate` at `fullchain.pem`, not `cert.pem`.         |
| `validation-failure`        | RFC 8460 §4.3 catch-all for anything not above.                            | TLS-version mismatch, cipher mismatch, mid-handshake reset.    | Inspect `failure-reason-code`. Modernise to TLS 1.2+: Postfix `smtpd_tls_protocols = >=TLSv1.2`. Update `ca-certificates`.                          |
| `tlsa-invalid`              | TLSA RR present but no records validate against the served cert.           | Let's Encrypt key rotated without pre-publishing new TLSA.     | Publish `3 1 1` SPKI SHA-256 at `_25._tcp.<mx-host>`. Pre-publish before rotation; use `certbot renew --reuse-key`.                                 |
| `dnssec-invalid`            | Validating resolver returned SERVFAIL/bogus on MX, A/AAAA, or TLSA.        | Expired RRSIG; missing DS at registrar; broken NSEC3.          | Run a validating local resolver (`unbound: validate: yes`). Re-sign with ECDSAP256SHA256. Push DS at the registrar.                                 |
| `dane-required`             | Sender mandates DANE; no usable DNSSEC-secure TLSA was found.              | TLSA published at `_25._tcp.<domain>` (wrong) instead of MX.   | Publish TLSA at `_25._tcp.<mx-host>` for **every** MX. Publish DS at registrar. (Postfix `dane-only`; Exim `hosts_require_dane`.)                   |
| `sts-policy-fetch-error`    | Couldn't GET `https://mta-sts.<domain>/.well-known/mta-sts.txt`.           | TCP timeout; 4xx/5xx; forbidden redirect; cert expired.        | nginx: `location = /.well-known/mta-sts.txt { default_type text/plain; return 200 "..."; }`. Bump `id=` after every policy edit.                    |
| `sts-policy-invalid`        | Policy fetched but failed RFC 8461 §3.2 parse.                             | UTF-8 BOM; CRLF; missing `version: STSv1`; invalid `mode:`.    | LF newlines; no BOM; `version: STSv1` first; `mode: testing\|enforce\|none`; `mx:` patterns; `max_age:` 0–31557600.                                 |
| `sts-webpki-invalid`        | `mta-sts.<domain>` HTTPS host failed PKIX validation.                      | Self-signed cert; expired cert; no SAN for the hostname.       | Publicly-trusted cert (Let's Encrypt etc.) with SAN `mta-sts.<domain>`. Automated renewal with reload hook on a host that's rarely visited.         |

Five of these eleven values have **no public verbatim JSON example** as of
April 2026: `starttls-not-supported`, `certificate-expired`, `tlsa-invalid`,
`dane-required`, `sts-policy-invalid`, and `sts-webpki-invalid`. Their
existence is documented at the log-line level (Postfix's `TLSRPT_README` shows
the exact mapping) but no operator has shared the corresponding aggregate JSON
publicly. That's a real gap in the corpus, not a comment on rarity in the
wild.

A few cross-cutting notes the per-row fixes don't fit. Let's Encrypt's OCSP
responders shut down on **6 August 2025**; legacy ACME configs that still set
OCSP-Must-Staple have been silently surfacing as `certificate-expired` and
`validation-failure` in TLS-RPT ever since. Postfix's TLSRPT client (Postfix
3.10) emits at most one final TLS handshake status per SMTP connection and
documents an average ~12-hour reporting lag, so Postfix-generated counts
aren't directly comparable to Microsoft- or Google-generated counts. Microsoft
retries TLSA lookups every 15 minutes for the first 30 minutes and then hourly
for 24 hours before issuing an NDR — DNSSEC rollover hiccups can be
retried-through but still emit `failed-session-count` entries.

For the DANE-flavoured rows (`tlsa-invalid`, `dnssec-invalid`, `dane-required`),
the [DANE TLSA validation](/learn/dane/) primer covers the operational
discipline you need. For the MTA-STS rows (`sts-policy-fetch-error`,
`sts-policy-invalid`, `sts-webpki-invalid`), [MTA-STS](/learn/mta-sts/)
explains the policy file. Two companion posts go deeper:
[What is DANE? (deeper walkthrough)](/blog/what-is-dane/) and
[MTA-STS example walkthrough](/blog/mta-sts-example/).

## Pairing TLS-RPT with MTA-STS and DANE

A common mental model treats TLS-RPT as "phase zero" — turn on monitoring
first, then layer policies on top. That model is wrong. TLS-RPT is **not a
freestanding monitoring phase**. It only produces useful signal when paired
with at least one TLS-enforcement policy; an MTA-STS policy in `mode: testing`
is the minimum.

The deployment order operators actually back is consistent across primary
sources:

1. **Publish `_smtp._tls` TXT and `_mta-sts` TXT in `mode: testing` together**
   as a paired deployment. TLS-RPT is the report channel for the testing-mode
   policy and is functionally useless without it.
2. **Monitor TLS-RPT for two to four weeks.**
   [security.gov.uk](https://www.security.gov.uk/policy-and-guidance/set-up-tls-rpt-and-mta-sts/)
   sets the floor at two weeks; NCSC-UK recommends one month.
3. **Promote MTA-STS to `mode: enforce`.** Bump the `id=` value in the
   `_mta-sts` TXT so caching senders re-fetch.
4. **Add DANE/TLSA only if DNSSEC is operationally trusted.** TLSA at
   `_25._tcp.<mx-host>`, with DS at the registrar.

One major standards body actively dissents from this order. **Germany's BSI
TR-03108 v2.0** mandates DANE for both inbound and outbound
(`TR-03108-05/06-M`), mandates sending and receiving TLS-RPT
(`TR-03108-09/10-M`), and only _recommends_ MTA-STS (`TR-03108-07/08-R`). DANE
has no testing mode by design, so a BSI-compliant deployment ships enforcement
and reporting simultaneously. If you're certifying for the BSI IT Security
Label, that's the order you follow; otherwise the NCSC + security.gov.uk
staged ramp is the safer default.

Why does the testing window matter? In October 2020, a Mail-in-a-Box operator
published an MTA-STS policy in `mode: enforce` with a stale `id=` value.
Google sent clean TLS-RPT reports daily. Microsoft Exchange Online silently
rejected mail for over a week with `LED=450 4.4.317` — and Microsoft sent
zero TLS-RPT reports during the entire incident. The lesson: monitoring is
necessary but not sufficient. TLS-RPT report coverage is uneven across
senders, and a non-emitter can break delivery without ever appearing in your
dashboard.

Generate the records once you're ready.
[Check your TLS-RPT record](/tools/tls-rpt-checker/) confirms the TXT syntax
and walks every `rua=` URI for reachability.
[Generate a TLS-RPT record](/tools/tls-rpt-generator/) builds a valid record
from a checklist.

## TLS-RPT for Google Workspace and Microsoft 365

The two largest email platforms are also the two largest TLS-RPT report
senders. Each has its own setup quirks.

### Google Workspace

Inbound TLS-RPT for hosted Workspace domains is a one-record DNS change.
Publish
`_smtp._tls.<your-domain> IN TXT "v=TLSRPTv1; rua=mailto:tls-reports@<your-domain>"`
at your DNS provider — not in the Admin Console — and Gmail's outbound senders
honour it on day one. Reports arrive in standard RFC 8460 JSON, gzipped,
daily.

Where to terminate the `rua` mailbox matters more than people expect. A
dedicated Google Group with external-sender allowed is the cleanest pattern;
alternatively, route to a third-party aggregator first (we'll come back to
ordering in a moment). For Gmail's MTA-STS validator, navigate Admin Console
→ Apps > Google Workspace > Gmail > Compliance > MTA-STS > Validate.

Outbound TLS-RPT emission needs no Workspace toggle. Gmail emits daily
aggregate reports for any domain that publishes a `_smtp._tls` TXT record —
there's no allowlist, no opt-in, no quota beyond standard rate limits. If you
publish the record, you'll start receiving Google reports within 48 hours.

### Microsoft 365 / Exchange Online

Microsoft 365 is where TLS-RPT setup gets opinionated. Two gotchas dominate.

**The first-`rua` bug.** Microsoft delivers TLS-RPT reports to **only the
first `rua=` URI** in your TXT record (URIports, August 2024). The common
pattern of listing your own mailbox first and a third-party aggregator second
loses all Microsoft data on the second endpoint. URIports' recommendation,
which we second: list your aggregator first.

**The volume threshold.** Microsoft requires at least two messages per UTC
24-hour window before generating any report at all. Low-volume domains see
Microsoft as a non-emitter — silence isn't success, it's the threshold not
being met.

For the rua mailbox itself, avoid Defender-quarantined shared mailboxes
(aggregate reports are a known false-positive trigger for some quarantine
policies). The preferred pattern is a no-quarantine distribution list to a
parser-aware mailbox.

Microsoft does **not** host customer MTA-STS policies for Exchange Online. Per
[Microsoft Learn](https://learn.microsoft.com/en-us/purview/enhancing-mail-flow-with-mta-sts),
customers must configure their own STS policy hosting. The recommended
pattern is an Azure Static Web App on `mta-sts.<domain>` with a custom-domain
managed cert, paired with the `_mta-sts` TXT record and the TLS-RPT TXT.

<Figure
  src="/images/blog/tls-rpt-report/tls-rpt-report_provider-quirks_table.svg"
  alt="Comparison table of Google Workspace versus Microsoft 365 TLS-RPT report behaviour across rua URI handling, volume threshold, report-id format, organization-name string, failure-reason-code population, and MTA-STS policy hosting"
  caption="The two largest report senders diverge on the fields that matter most for setup — rua handling, the two-message volume threshold, and who hosts mta-sts.txt."
/>

For the broader sender-side picture on these two platforms,
[Google + Yahoo sender requirements](/blog/google-yahoo-dmarc-requirements/)
and [Microsoft DMARC enforcement](/blog/microsoft-dmarc-enforcement/) cover
the DMARC and SPF angles. TLS-RPT is the third leg of the stool.

## TLS-RPT for Postfix and Exim

Self-hosted MTAs split sharply on TLS-RPT support: Postfix has gone all-in,
Exim has not.

**Postfix 3.10+** ships native TLS-RPT support via
[libtlsrpt](https://github.com/sys4/tlsrpt-reporter). Wire it into `main.cf`:

<CodeBlock
  filename="main.cf"
  lang="ini"
  code={`smtp_tlsrpt_enable = yes
smtp_tlsrpt_socket_name = /var/run/tlsrpt.sock`}
/>

Then run sys4's `tlsrpt-collectd` and `tlsrpt-reporter` daemons. They populate
`/etc/tlsrpt/reportd.cfg` with `organization_name`, `contact_info`, and
`sender_address` — the values that Postfix-emitted reports will carry in their
`organization-name` and `contact-info` fields. Reports are aggregated to
SQLite, generated against the RFC 8460 schema, and dispatched via SMTP or
HTTPS POST. The full reference is
[Postfix TLSRPT_README](https://www.postfix.org/TLSRPT_README.html).

For **Postfix &lt; 3.10** or operators not adopting libtlsrpt, TLS-RPT
_consumption_ (parsing reports about your own MX) is well-supported by
parsedmarc. TLS-RPT _emission_ (generating reports about other people's MX
you delivered to) is not.

**Exim** is, as a TLS-RPT emitter, a dead-end. The Arch Wiki states it
bluntly: "Exim only supports DANE and not MTA-STS or TLS-RPT." Exim's source
carries no TLS-RPT reporter, and as of April 2026 there's no roadmap
commitment. Operators who need to emit TLS-RPT from an Exim site front it
with a Postfix 3.10+ relay or accept the gap.

While we're correcting the Arch Wiki: that page calls TLS-RPT reports "XML
formatted." They aren't. TLS-RPT reports are gzipped JSON conforming to
[RFC 8460 §4](https://datatracker.ietf.org/doc/html/rfc8460#section-4) — the
only related XML is DMARC's `aggregate-feedback` schema, which is a different
protocol entirely.

## How DMARCguard delivers TLS-RPT reports

DMARCguard ingests `mailto:` rua endpoints, gunzips the attachment, parses
the RFC 8460 schema, validates each `result-type` against the IANA registry,
and renders the failure details with sender-IP attribution and remediation
guidance linked inline. Every per-result-type cell is one click away from the
corresponding fix, with the IANA-verbatim hyphenated string preserved so what
you see in the dashboard matches what `dig` and `jq` show against the raw
report.

What separates this from generic parsedmarc / Mailhardener / PowerDMARC
dashboards: the field-name schism is handled. DMARCguard reads both
`additional-information` (schema-faithful) and `additional-info-uri`
(prose-faithful) so reports from mox-based senders don't disappear into a
silent drop the way they do in parsedmarc. The Microsoft first-`rua` bug is
surfaced as a setup warning rather than a missing-data mystery. And the
`sts-policy-invalid` body diff between testing and enforce policies is
rendered side-by-side, not buried in raw text.

If you want to see TLS-RPT working without a signup:
[check your TLS-RPT record](/tools/tls-rpt-checker/),
[generate a TLS-RPT record](/tools/tls-rpt-generator/), or paste a sample into
the [TLS Report Analyzer](/tools/tls-report-analyzer/). All three are free.
Monitoring all seven core protocols on the free tier (nine on Pro) is the
next step when you're ready.

<CTA
  title="Stop guessing whether your TLS-RPT is working"
  description="Check your _smtp._tls record, walk every rua= URI for reachability, and confirm reporting mailboxes are reachable — no signup, no email gate."
  href="/tools/tls-rpt-checker/"
  label="Check TLS-RPT record"
/>

## Frequently asked questions

### What is a TLS-RPT report?

A TLS-RPT report is a once-per-UTC-day JSON aggregate that a sending mail
server emails to a recipient domain, summarising every SMTP TLS session
attempted that day. Defined in RFC 8460, it lists successes, failures, the
MTA-STS or DANE policy applied, and an IANA result type for each fault.

### How do I check my TLS-RPT record?

Run `dig +short TXT _smtp._tls.<your-domain>` to see the published policy.
For deeper validation, paste the domain into
[DMARCguard's TLS-RPT checker](/tools/tls-rpt-checker/) — it parses the TXT
syntax, walks every `rua=` URI, and confirms the reporting mailbox is
reachable so senders won't silently drop reports.

### How is a TLS-RPT report delivered?

Reports are gzipped JSON delivered over `mailto:` (DKIM-signed, content type
`application/tlsrpt+gzip`) or HTTPS POST. RFC 8460 §3 requires delivery even
when TLS to the report mailbox fails — so reports may arrive in cleartext when
the very condition they describe blocks encryption.

### Do I need TLS-RPT if I already have MTA-STS or DANE?

Yes. TLS-RPT is the only feedback channel for an MTA-STS policy in
`mode: testing` and the only way to know a DANE rollover hasn't broken inbound
mail. Without it, an enforce-mode policy can silently bounce real mail —
exactly what happened to a Mail-in-a-Box operator with Outlook in October
2020.

### Why am I not getting Microsoft TLS-RPT reports?

Two known causes. Microsoft delivers reports to only the FIRST `rua=` URI in
your TXT record, so a third-party aggregator listed second receives nothing.
Microsoft also requires at least two messages per 24-hour UTC window before
generating any report at all
([URIports, August 2024](https://www.uriports.com/blog/microsoft-tls-rpt-rua-flaw/)).

### What does `sts-policy-fetch-error` mean in a TLS-RPT report?

The sender saw a valid `_mta-sts` TXT record but couldn't fetch
`https://mta-sts.<domain>/.well-known/mta-sts.txt` — a TCP timeout, a 4xx/5xx
response, or a forbidden redirect. Fix it by serving plain text with no
redirects, then bump the policy `id=` so caching senders re-fetch.

### How often are TLS-RPT reports sent?

Once per UTC day per sender, recipient, and policy tuple, per RFC 8460 §4.1,
with up to four hours of randomised delay. Postfix 3.10's reporter documents
an additional ~12-hour processing lag, so a report covering Monday usually
arrives mid-Tuesday.

## Conclusion

A TLS-RPT report is daily JSON visibility for SMTP TLS — the only standard
channel that tells a recipient domain when senders broke or downgraded the
encrypted handshake. Every report distills to the eleven IANA result types
covered above, and recovering signal means matching each verbatim string to
the right fix on the right side of the conversation. Deploy paired with
MTA-STS in `mode: testing`, monitor for two to four weeks, and only then
promote — and remember that Microsoft's first-`rua` bug and the two-message
volume threshold are the two most common reasons operators think they have no
Microsoft data.

Want to start?
[Check your TLS-RPT record free with DMARCguard's TLS-RPT checker](/tools/tls-rpt-checker/) —
no signup required. Or drop a sample into the
[TLS Report Analyzer](/tools/tls-report-analyzer/) and watch the IANA-token
annotation render automatically. For the protocol fundamentals, the
[TLS-RPT primer](/learn/tls-rpt/) is the next read.