27 May 2026 · 11 min read
The reporting half of DMARC is the half that actually does work for you. The policy half (p=none, p=quarantine, p=reject) tells receivers what to do with mail that fails. The reporting half, carried by the rua and ruf tags, tells receivers where to send the data that lets you reach enforcement safely in the first place. Both rua and ruf take a list of URIs, and the DMARC specification deliberately allows two URI schemes: mailto: and https:. In practice almost every working DMARC record in the world uses mailto: and nothing else, and there are concrete, technical reasons for that, not just habit.
This article is specifically about the URI in those tags: the difference between the mailto: and https: schemes, the optional size-limit syntax the specification defines, what receivers actually honour, and how a report-processing pipeline ingests the data once it arrives. It is not a general DMARC explainer. If you want the broader picture of what the two report types contain, DMARC RUA and RUF reports covers that, and reading your first DMARC report walks through a real file. Here we stay on the wire format of the destination itself.
Where the URI lives in the record
The two reporting tags sit inside the ordinary DMARC TXT record at _dmarc.<your-domain>. A complete record with both report types configured looks like this:
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc-rua@example.com; ruf=mailto:dmarc-ruf@example.com; fo=1; ri=86400"
ruais the destination for aggregate reports: the daily XML census of who sent mail using your domain, with per-source counts and pass/fail/alignment results. This is the data you actually use to get top=reject.rufis the destination for failure reports, historically called forensic reports: a near-real-time, per-message copy of an individual message that failed DMARC. Far fewer receivers send these, for privacy reasons we cover below.
Both tags take a comma-separated list of URIs. Each URI must be a valid mailto: or https: (or http:) URI per RFC 7489 Section 6.2. You can mix them, list several of each, and attach a per-URI size limit. The two tags are independent: you can publish rua without ruf, which is what most domains should do.
Before you read further, it is worth seeing your own record parsed cleanly. Paste your domain into the DMARC checker and it will split out the rua and ruf URIs and flag anything malformed. If you are building a record from scratch, the DMARC record generator writes the tags in the correct order with valid syntax.
The two URI schemes the specification allows
RFC 7489 defines exactly which URI schemes are valid in rua and ruf, and it leaves the door open to more than one. In practice you will only ever meet two.
mailto: the scheme everyone uses
A mailto: URI tells the reporting receiver to email the report to a mailbox. For aggregate reports the receiver builds the XML document, compresses it (almost always gzip, historically sometimes zip), attaches it to an email, and sends that email to the address in the URI. The Subject line follows a defined convention so that automated processors can recognise reports without opening them:
Report Domain: example.com Submitter: google.com Report-ID: 17654987654321
A mailto: URI looks exactly like an email address with the scheme prefix:
rua=mailto:dmarc-rua@example.com
You can list more than one, separated by commas, and they do not have to be on your own domain:
rua=mailto:dmarc-rua@example.com,mailto:reports@your-analytics-provider.example
That second form is how every hosted DMARC analytics service works. You point rua at the provider's ingestion mailbox, the provider receives the gzipped XML by email, parses it, and shows you a dashboard. There is no API call, no webhook, no polling: the receiver pushes the report to a mailbox, and the analyser reads that mailbox.
https: the scheme almost nobody honours
An https: URI tells the receiver to HTTP POST the report to a URL instead of emailing it:
rua=https://dmarc.example.com/ingest
On paper this is attractive. An HTTP POST is structured, immediate, easy to authenticate, and does not need a mailbox, an inbound mail server, or attachment handling. If you were designing DMARC reporting from scratch today, HTTPS delivery is probably what you would choose.
In reality, the large reporting receivers do not implement HTTPS delivery. Google, Microsoft, Yahoo and the other high-volume reporters send aggregate reports by email to mailto: URIs. If you publish only an https: URI for rua, you will receive almost nothing, because the receivers that generate the overwhelming majority of report volume simply ignore the scheme. This is the single most important practical fact in this whole topic: HTTPS reporting URIs are valid syntax that does not work in the field. Publish mailto: or you get no data.
There is a small amount of historical baggage here. The original DMARC drafts and early deployments experimented with HTTP/HTTPS POST delivery, and the scheme was kept in the specification, but the senders never converged on it. So the scheme survives in the grammar and is dead in practice. Treat https: in rua/ruf as a trap: a thing the spec permits that will silently cost you your reporting if you rely on it.
Why mailto won, in technical terms
It is worth understanding why email beat HTTPS for report delivery, because it explains a lot about how the ecosystem behaves.
- Receivers already run outbound mail infrastructure. A mailbox provider that evaluates DMARC is, by definition, already sending email at scale. Emitting a report as one more outbound message reuses queues, retries, rate limiting and reputation handling they already operate. Standing up an HTTP client with its own retry and backoff policy for a side feature was extra work nobody prioritised.
- Email retries are free and well understood. If your report mailbox is briefly unreachable, the receiver's MTA retries on the normal schedule. An HTTP POST to a flaky endpoint has weaker, less standardised retry semantics, and a 500 from your ingest endpoint could simply lose the report.
- No inbound endpoint to secure. With
mailto:, the domain owner does not have to expose and harden a public HTTPS endpoint that the entire internet can POST arbitrary XML to. The attack surface of an ingestion mailbox is smaller and more familiar. - It composes with delegation trivially. Pointing
ruaat a third-party mailbox is a one-line change and needs no shared secret. An HTTPS endpoint usually wants authentication, which the DMARC URI has no place to carry.
The result is a de facto standard: aggregate and failure reports travel as gzipped XML email attachments to mailto: addresses, and any tooling you build or buy is built around ingesting a mailbox.
The size-limit suffix on a URI
Both schemes support an optional maximum report size appended to the URI with an exclamation mark. The syntax is ! followed by a number and an optional unit letter:
rua=mailto:dmarc-rua@example.com!10m
This says: do not send me an aggregate report larger than 10 megabytes. The unit letters defined by RFC 7489 Section 6.2 are:
kkilobytes (units of 10^3 bytes)mmegabytes (10^6)ggigabytes (10^9)tterabytes (10^12)
With no unit letter, the number is plain bytes. So !10m is ten million bytes and !500k is five hundred thousand bytes. The size refers to the size of the report the receiver intends to send. If a generated report exceeds the stated limit, the receiver is expected not to send the oversized report, and may instead send a short error report indicating it could not deliver within the limit. Crucially, it does not silently truncate the XML into something a parser would choke on: you either get a valid report or you get told it was too big.
In real life you almost never need this. Aggregate reports are compressed XML and are small; even a busy domain's daily report from a major receiver is usually well under a megabyte. The size suffix matters mainly to providers ingesting reports for thousands of customer domains, where a single oversized report from a misbehaving sender could affect a shared pipeline. For a normal domain, omit it entirely. If you do set one, set it high (!10m or more), because a too-low limit means you lose reports you would otherwise have wanted.
External destination verification: the bit people forget
Here is the rule that trips up most people delegating reports to an analytics provider. If the rua/ruf mailbox is on a different organisational domain from the domain being reported on, the receiver must, per RFC 7489 Section 7.1, perform an external destination verification before it will send any reports there. This exists to stop you (or an attacker) from naming an innocent third party as the dumping ground for someone else's report traffic.
The check works like this. Suppose example.com publishes:
rua=mailto:reports@analytics-provider.example
The destination domain analytics-provider.example is different from example.com, so before sending, the receiver looks up a TXT record at a specially named host under the destination domain:
example.com._report._dmarc.analytics-provider.example. IN TXT "v=DMARC1"
That record is the destination domain saying, in effect, yes, I consent to receive DMARC reports on behalf of example.com. The format is <reported-domain>._report._dmarc.<destination-domain>. There is also a wildcard form, where the destination publishes a single record that authorises reports for any reporting domain, which is what hosted providers use so they do not need one record per customer.
The practical consequences:
- If you point
ruaat a provider and do not see reports flowing, the missing external verification record is one of the first things to check. The provider should publish it (or tell you to), and a hosted provider almost always handles this for you. - The
https:scheme is subject to the same external verification rule, which is yet another reason it adds complexity for no benefit when the receivers ignore it anyway. - This is one of the most common causes of "I set up DMARC reporting and nothing arrived". It is covered from the troubleshooting angle in DMARC reports are empty.
You can confirm the destination consent record is in place with a TXT lookup. The DMARC checker flags an external rua destination so you know verification is required, and a plain DNS record checker lets you query the _report._dmarc host directly.
What actually arrives, and how analysers ingest it
Once the URIs are valid and verification is satisfied, here is the lifecycle of an aggregate report from receiver to dashboard.
- Aggregation window. Over the interval requested by your
ritag (default 86400 seconds, one day), the receiver tallies every message bearing your From domain: source IP, message count, SPF result and domain, DKIM result andd=domain, and the DMARC alignment outcome and disposition for each.riis a request; receivers send roughly daily regardless and do not honour very short intervals. - Report generation. At the end of the window the receiver serialises the tally into an XML document conforming to the DMARC aggregate report schema. The document has a
report_metadatablock (who sent it, the report ID, the date range), apolicy_publishedblock (the record they saw), and a series ofrecordrows, one per source IP and result combination. - Compression and packaging. The XML is gzipped. The filename follows the convention
receiver!reporteddomain!begin-timestamp!end-timestamp!unique.xml.gz, for examplegoogle.com!example.com!1718668800!1718755200.xml.gz. That structured filename is itself metadata your pipeline can parse. - Delivery. The gzipped file is attached to an email and sent to your
mailto:address, with the conventional Subject line. For anhttps:URI it would be POSTed, but as established, this rarely happens. - Ingestion. Your processor (self-built or a hosted analyser) watches the report mailbox, fetches new messages, detaches and decompresses the
.gz, validates the XML against the schema, and inserts the rows into a database keyed by source, date and authentication result. - Aggregation and presentation. The processor groups rows across all reporting receivers, resolves source IPs to sending organisations, and shows you a per-sender view of aligned versus unaligned volume over time. This grouped view, not the raw XML, is what you make policy decisions from.
The reason a tool exists for step 6 is that raw aggregate XML is unreadable at any real volume and arrives from dozens of receivers in slightly different dialects. Paste a report into the DMARC report analyzer and it performs steps 5 and 6 for a single file so you can see the structure. For continuous ingestion across every receiver, you want a mailbox-backed pipeline doing it automatically, which is what continuous DMARC monitoring provides.
Failure (RUF) reports are a special case
Everything above describes aggregate (rua) reports. Failure reports (ruf) follow the same URI rules: comma-separated mailto:/https: list, size suffixes, external verification. But two things differ in practice.
- Almost no major receiver sends them any more. Failure reports contain headers and sometimes content from individual real messages, which is personal data. After privacy regulation tightened, Google, Microsoft and most large providers stopped emitting
rufreports almost entirely. Publishingrufis mostly harmless but largely unproductive: you will receive a trickle, if anything. - When they do arrive, they are per-message, not aggregated. The format is typically an ARF (Abuse Reporting Format) message wrapping a redacted copy of the failing message. The
fotag controls when one is generated:fo=0(default) only when every mechanism fails,fo=1when any aligned mechanism fails.fo=1is what you want if you publishrufat all, but it only matters for the receivers still sending failure reports.
For these reasons, the standard advice is to publish rua and treat ruf as optional. The aggregate stream is what gets you to enforcement.
Putting it together: a record you can copy
For a domain at the start of its journey, monitoring everything and sending aggregate data to your own mailbox plus an analytics provider:
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com,mailto:reports@analytics-provider.example; fo=1; ri=86400"
If you want failure reports too, despite the low yield:
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com; ruf=mailto:dmarc@example.com; fo=1; ri=86400"
A few rules of thumb that fall out of everything above:
- Always use
mailto:. Never rely onhttps:forruaorruf; the receivers that matter ignore it. - Keep the report mailbox a dedicated address, not a person's inbox. It will receive a steady stream of gzipped attachments that you never want a human to open by hand.
- If the mailbox is on a different domain, ensure the external verification record exists, or no reports arrive.
- Leave the size suffix off unless you operate a shared pipeline, and if you set one, set it generously.
- Publish
ruafrom day one ofp=none. The reports are the entire point of thenonephase; without them you are flying blind and cannot safely tighten toquarantineorreject. Why p=none is not real protection explains why the monitoring phase only earns its keep when you are actually reading the data it produces.
The takeaway
The choice between mailto: and https: reporting URIs looks like a real decision and is not one: the specification permits both, the field honours only mailto:, and a record that bets on HTTPS delivery quietly receives nothing. Publish mailto: addresses, point them at a dedicated mailbox or a provider's ingestion address, satisfy external destination verification when the mailbox lives on another domain, and let an analyser turn the gzipped XML into a per-sender view you can act on. The size suffix is a niche control most domains should leave alone, and ruf is a near-dead channel you can usually skip.
Check that your own record's reporting URIs are valid and that an external destination is verified with the DMARC checker, and if you would rather not run an ingestion mailbox and a parser yourself, our done-for-you DMARC service receives the reports, reads them, and takes your domain from p=none to p=reject without losing legitimate mail along the way.