The DMARC record is a TXT record at _dmarc under the domain. It is a short list of tags, and every one of them changes what receivers do. Three real records, then each tag in turn.
Three records, read as policy statements
"v=DMARC1; p=quarantine; sp=reject; pct=100; rua=mailto:dmarc@github.com; ruf=mailto:dmarc@github.com; fo=1"
"v=DMARC1;p=reject;aspf=s;adkim=s;pct=100;fo=0;ri=86400; rua=mailto:dmarc_agg@vali.email;"
"v=DMARC1; p=reject; rua=mailto:d@rua.agari.com,mailto:dmarc_agg@vali.email; ruf=mailto:d@ruf.agari.com,mailto:MTc4Mzcw@ruf.vali.email"
The tags
v=DMARC1; p=quarantine; sp=reject; adkim=r; aspf=r; pct=100;rua=mailto:agg@example.com; ruf=mailto:forensic@example.com;fo=1; ri=86400
v=DMARC1— required, and must be first. Without it the record is not a DMARC record.p=— the policy:none,quarantineorreject. Required.sp=— policy for subdomains. If absent, subdomains inheritp=.adkim=,aspf=— alignment mode,rrelaxed (default) orsstrict.pct=— apply the policy to this percentage of failing messages. Defaults to 100.rua=— where to send aggregate reports.ruf=— where to send per-message failure reports.fo=— when to generate failure reports.1means any failure, not only total failure.ri=— requested reporting interval in seconds. Defaults to 86400, and receivers largely ignore anything else.
The three policies
| Policy | Asks receivers to | Use it when |
|---|---|---|
| p=none | Do nothing differently — but still send reports. | You are discovering your senders. This is monitoring, not protection. |
| p=quarantine | Treat failing mail as suspicious. In practice, spam folder. | You believe your inventory is complete and want a survivable first step. |
| p=reject | Refuse failing mail at SMTP time. | You are confident. Failing mail bounces rather than landing in a folder someone might check. |
p=none protects nothing
It is a monitoring request. A domain sitting at p=none is exactly as spoofable as a domain with no DMARC record at all — the only difference is that the owner now receives reports about it. That is genuinely valuable, and it is not protection. Domains that published p=none years ago and stopped there have the paperwork and none of the benefit.
pct, and why it disappoints
pct=25 asks receivers to apply the policy to a quarter of failing messages and treat the rest as the next weaker policy. It is designed as a ramp.
In practice it is a blunt instrument. The sampling is per-message and per-receiver, so a single sender does not fail consistently — it fails a quarter of the time, which makes problems intermittent and much harder to diagnose than a clean failure. It is genuinely useful for the reject step, where the difference between a bounce and a spam folder is material; below that, moving p= is usually clearer than tuning pct.
sp, the tag worth setting early
Subdomains inherit p= unless sp= says otherwise. That default matters because organisations have many subdomains that send no mail at all, and an attacker will happily use invoices.example.com if nothing stops them.
GitHub’s record above is a good pattern: p=quarantine on the main domain, which has real senders and real risk of a false positive, and sp=reject on subdomains, where there is much less to break. Setting sp=reject is often the earliest meaningful enforcement an organisation can safely take.
rua, and the record that makes it work
Aggregate reports are the point of deploying DMARC at all. One detail sinks a great many deployments: if the reporting address is at a different domain from the one being reported on, that other domain must publish a record authorising it — RFC 7489 §7.1. Without it, conforming receivers drop the reports silently, the DMARC record looks perfect, and nothing ever arrives.
This is common enough, and subtle enough, that it has its own reference article; the link is at the end of this lesson.
- Multiple destinations are allowed, comma-separated. PayPal’s record above sends to two.
- Reports are XML, gzipped, sent by email, typically daily. They contain counts and source addresses — never message content.