DMARC Engine
Home/Blog/The DMARC record explained, tag by tag
Blog

The DMARC record explained, tag by tag

A plain-English reference to every tag in a DMARC record: v, p, sp, rua, ruf, pct, adkim, aspf, fo, rf and ri. What each one does, the exact syntax it expects and the sensible default to reach for.

22 June 2026 · 15 min read

The DMARC record explained, tag by tag

A DMARC record is one line of text published in your DNS, and yet that single line decides whether the rest of the world will accept or reject mail claiming to come from your domain. It is deceptively short. A working record can be as compact as v=DMARC1; p=none; rua=mailto:reports@example.com, and a hardened one rarely runs past a few hundred characters. But every tag inside it carries weight, and a misplaced semicolon or a misunderstood default can quietly undo months of work.

This guide walks through every tag you can put in a DMARC record, one at a time: what it means, the exact syntax it expects, the values it accepts, and the sensible default to reach for. By the end you should be able to read any DMARC record at a glance and know precisely what it is telling receiving mail servers to do.

If you just want to inspect a live record without learning the grammar first, paste your domain into the DMARC checker and it will parse and explain every tag for you. If you would rather build one from scratch, the DMARC record generator produces valid syntax from a few choices. This article is the reference that sits behind both.

What a DMARC record actually is

DMARC stands for Domain-based Message Authentication, Reporting and Conformance. The record itself is a single DNS TXT entry published at a fixed, predictable hostname: the label _dmarc prefixed to your domain. For example.com, the record lives at _dmarc.example.com. For a subdomain like mail.example.com, it would live at _dmarc.mail.example.com, though as you will see, subdomains usually inherit policy from the parent.

The value of that TXT record is a list of tag-value pairs separated by semicolons. Each pair takes the form tag=value. Whitespace around the semicolons is tolerated by parsers, so both of these are valid and identical in meaning:

DNS record
v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com
v=DMARC1;p=quarantine;rua=mailto:dmarc@example.com

Tags are case-insensitive in their names, but some values are not. The mechanism keywords (none, quarantine, reject, r, s) are conventionally lower-case and you should keep them that way. The v=DMARC1 token is the one true exception to free ordering: it must come first, exactly as written, or receivers will treat the record as invalid and ignore it entirely.

A crucial point that trips people up: DMARC does not authenticate anything on its own. It is a policy layer that sits on top of two underlying checks, SPF and DKIM. DMARC asks whether either of those passed and whether the domain they passed for lines up with the domain in the visible From: address. That last part is called alignment, and several DMARC tags exist purely to tune how strict that alignment must be. If the concepts of SPF and DKIM are hazy, the SPF checker and DKIM checker are the quickest way to see them working on a real domain, and the glossary defines the terms used throughout.

v: the version tag (required, always first)

DNS record
v=DMARC1

The v tag declares the DMARC version. Today there is exactly one valid value: DMARC1. This tag is mandatory, it must be the first tag in the record, and it must be spelled precisely as DMARC1 with no lower-case variation accepted in practice.

Its job is more important than it looks. Receivers locate your DMARC record by querying _dmarc.yourdomain and then scanning the returned TXT records for one that begins with v=DMARC1. If a domain has several TXT records at that name (which it never should for DMARC), or if the version token is malformed, the record is discarded as though it were not there. A surprising number of broken DMARC deployments come down to a stray second record or a typo in this opening tag. There is no sensible alternative value: it is always v=DMARC1, full stop.

p: the policy tag (required)

Example
p=none
p=quarantine
p=reject

The p tag is the heart of DMARC. It tells receiving servers what to do with a message that claims to be from your domain but fails the DMARC check (meaning neither SPF nor DKIM passed in an aligned way). It accepts three values:

  • none asks the receiver to take no special action. Failing mail is still delivered as normal. This is monitor-only mode: you collect reports and learn who is sending as you, but nothing is blocked.
  • quarantine asks the receiver to treat failing mail as suspicious, typically routing it to the spam or junk folder rather than the inbox.
  • reject asks the receiver to refuse failing mail outright at the SMTP layer, so it never reaches the recipient at all.

p is required: a DMARC record without it is invalid. The sensible default when you first publish is p=none, because it lets you observe traffic without risking legitimate mail. But none is a starting line, not a finish line. A record left at p=none forever protects nobody, since it never tells receivers to stop a spoofed message. The whole point of DMARC is to move in stages from none to quarantine to reject once your reports confirm that every legitimate source is aligned. We cover why standing still is dangerous in Why p=none gives a false sense of security, and the staged rollout itself is what the done-for-you DMARC service automates.

sp: the subdomain policy tag (optional)

Example
sp=reject

The sp tag sets a separate policy for subdomains of your domain. If you publish DMARC on example.com with p=quarantine and sp=reject, then mail failing DMARC from example.com itself is quarantined, while failing mail from anything.example.com is rejected.

When sp is absent, subdomains inherit the value of p. That inheritance is the part to remember, because it has real security consequences. Attackers love subdomains precisely because organisations forget about them: accounts.example.com or news.example.com may have no mail flow at all, yet without an explicit policy they are only as protected as the parent record makes them.

The sensible approach is usually to leave sp unset early on so subdomains inherit your cautious parent policy, then, once you reach enforcement, consider setting sp=reject to slam the door on unused subdomains even if the organisational policy is still quarantine. There is real nuance to how subdomains and DMARC interact, especially around whether a subdomain needs its own record at all, which we unpack in Does every subdomain need its own DMARC record?.

Example
rua=mailto:dmarc@example.com
rua=mailto:dmarc@example.com,mailto:reports@thirdparty.com

The rua tag tells receivers where to send aggregate reports. These are the daily XML summaries that mailbox providers generate, one per sending source, listing how many messages they saw from each IP address and whether those messages passed SPF, DKIM and DMARC alignment. Aggregate reports are the single most valuable thing DMARC gives you, because they reveal every system sending mail as your domain, both the legitimate ones you forgot about and the spoofers you never knew existed.

The value is one or more mailto: URIs separated by commas. RFC 7489 also allowed a size cap after the address, such as !10m for ten megabytes; RFC 9989 removed it and reporters should ignore it, so leave it off. If the reporting address is on a different domain from the one being reported on, that other domain needs an authorisation record, but for same-domain reporting you can ignore that detail.

There is no formal default, but the practical default is: always include rua. A DMARC record without it is technically valid yet operationally blind, because you get no visibility into your own mail. Those XML files are dense and not meant for human eyes, so feed them into the DMARC report analyser to turn them into a readable picture, or let continuous monitoring parse them for you and alert on changes. For a guided tour of what the raw data contains, read Reading your first DMARC aggregate report.

ruf: forensic report address (optional, use with care)

Example
ruf=mailto:forensics@example.com

The ruf tag requests forensic reports, also called failure reports. Unlike aggregates, which are statistical summaries, a forensic report is generated per failing message and contains a redacted copy of the message itself: headers, and sometimes parts of the body, for an individual email that failed DMARC. In principle this lets you inspect exactly what a spoofed message looked like.

In practice, ruf is far less useful than it sounds, for two reasons. First, the major mailbox providers largely stopped sending forensic reports years ago over privacy concerns, since the reports can contain personal data from real recipients. So even with ruf configured you may receive almost nothing. Second, what you do receive can be a firehose during an active spoofing campaign, landing real message content in your inbox.

The syntax mirrors rua: one or more mailto: URIs, comma-separated. A companion tag, fo, controls when forensic reports are generated (covered below). The sensible default is to leave ruf out unless you have a specific investigative need and a mailbox prepared to handle sensitive content. Aggregate reporting via rua does the heavy lifting for nearly everyone.

t: test mode (optional), which replaced pct

Example
t=y

The t tag tells receivers whether you are testing your policy. With t=y, a receiver on RFC 9989 applies one level less than your published policy: p=quarantine; t=y is treated as p=none, and p=reject; t=y as p=quarantine. The default, t=n, applies the policy as written. It replaced the old pct sampling tag, which RFC 9989 removed because receivers rarely applied values other than 0 and 100 accurately.

Use t=y as a brief confidence check when first moving to quarantine or reject, then remove it. Sitting permanently at t=y leaves you one level below the policy you published, which defeats the purpose.

One caveat worth knowing: receivers still on RFC 7489 ignore t= and apply your policy in full, so treat it as a soft step and rely on your reports to tell you when it is safe to remove it. A leftover pct= in an older record is ignored by receivers on the new standard; what changed in RFC 9989 covers what to do with it.

adkim: DKIM alignment mode (optional)

Example
adkim=r
adkim=s

The adkim tag controls how strictly DKIM alignment is checked. DKIM signs a message and ties the signature to a domain (the d= value in the DKIM signature). For DMARC to count that signature as a pass, the signing domain has to align with the From: domain. The adkim tag decides what "align" means:

  • r is relaxed mode (the default). The signing domain only needs to share the same organisational domain as the From: address. A signature from mail.example.com aligns with a From: of example.com.
  • s is strict mode. The signing domain must match the From: domain exactly. A signature from mail.example.com would not align with example.com under strict mode.

The default is r, and relaxed is the right choice for almost everyone, because it accommodates the normal reality of subdomains and sending platforms while still preventing cross-organisation spoofing. Reach for adkim=s only when you have a specific reason to demand exact-domain signatures and you are confident every legitimate signer uses the precise From: domain.

aspf: SPF alignment mode (optional)

Example
aspf=r
aspf=s

The aspf tag is the SPF counterpart of adkim. It controls how strictly SPF alignment is checked. SPF validates the envelope sender (the MAIL FROM or Return-Path domain), and DMARC requires that domain to align with the visible From: domain. The values mirror DKIM:

  • r is relaxed (the default): the Return-Path domain and the From: domain need only share an organisational domain.
  • s is strict: they must match exactly.

The default is r, and again relaxed suits most senders. This matters more than it might seem, because many email service providers set a Return-Path on their own subdomain (for bounce handling) while sending From: your domain. Under relaxed SPF that still aligns; under strict it would not, and you could break SPF alignment for legitimate mail without realising it. Use aspf=s sparingly. If you are wrestling with SPF alignment at all, Why your service is not aligned at p=reject walks through the most common causes.

fo: forensic reporting options (optional)

Example
fo=1

The fo tag fine-tunes when a receiver should generate the failure reports requested by ruf. It only has an effect if you have also published a ruf address. It accepts these values:

  • 0 (the default): generate a report only if both SPF and DKIM fail to produce an aligned pass.
  • 1: generate a report if either SPF or DKIM fails to produce an aligned pass. This is the most useful setting, because it catches cases where one mechanism passed and the other did not.
  • d: generate a report whenever DKIM fails to verify, regardless of alignment.
  • s: generate a report whenever SPF fails, regardless of alignment.

You can combine d and s with a colon, as in fo=d:s. The sensible default, if you collect forensic reports at all, is fo=1, since the standard default of 0 is needlessly narrow. But remember the earlier caveat: most providers no longer send these reports, so fo often has no observable effect.

rf: report format (removed in RFC 9989)

Example
rf=afrf

The rf tag named the format for forensic (failure) reports. The only value ever used was afrf, the Authentication Failure Reporting Format, which was also the default, so there was never another format to choose. RFC 9989 removed the tag. If you see rf=afrf in a record, it does nothing. Leave it out.

ri: reporting interval (removed in RFC 9989)

Example
ri=86400

The ri tag requested how often, in seconds, you would like aggregate reports, with a default of 86400, once per day. Anything other than a daily report was best effort, and in practice the overwhelming majority send aggregate reports once every twenty-four hours regardless of what you ask for. RFC 9989 removed the tag, and RFC 9990 says a report typically covers a single UTC day. If you see ri= in a record, it does nothing. Leave it out.

Putting the tags together

Tags are independent, but they tell a story when read in sequence. Here is a record at the start of a deployment, monitoring only and gathering data:

DNS record
v=DMARC1; p=none; rua=mailto:dmarc@example.com

Here is the same domain partway through rollout, testing quarantine while still watching closely:

DNS record
v=DMARC1; p=quarantine; t=y; rua=mailto:dmarc@example.com; aspf=r; adkim=r

And here is a fully enforced record, the destination every domain should aim for, rejecting spoofed mail outright and protecting unused subdomains with an explicit subdomain policy:

DNS record
v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc@example.com; aspf=r; adkim=r

Notice what is absent from the enforced record: no t (because the default n is correct), no ruf or fo (because forensic reports add little), no rf or ri (because RFC 9989 removed them). A clean DMARC record sets only the tags that change a default. Everything else is noise.

A quick reference to the defaults

When a tag is omitted, the receiver assumes a default. Knowing these saves you from publishing tags that do nothing:

  • v has no default; it is required and must be DMARC1.
  • p has no default; it is required.
  • sp defaults to whatever p is set to.
  • rua has no default; omitting it simply means no aggregate reports.
  • ruf has no default; omitting it means no forensic reports.
  • t defaults to n (the policy applies as written).
  • adkim defaults to r (relaxed).
  • aspf defaults to r (relaxed).
  • fo defaults to 0.
  • rf and ri have no default any more; RFC 9989 removed both.

Common mistakes to avoid

A few errors come up again and again. The v=DMARC1 token must be first and exact; anything else invalidates the record. There must be only one DMARC record at _dmarc.yourdomain; publishing two is a frequent cause of silent failure. The p tag is mandatory, so a record that jumps straight to rua without a policy will be rejected by parsers. Reporting addresses must be valid mailto: URIs, and if they live on a different domain you need the matching authorisation record or those reports will never arrive. Finally, do not confuse strict and relaxed: setting aspf=s or adkim=s without understanding your senders is one of the surest ways to break alignment for legitimate mail. Run your draft through the DMARC checker before you publish, and it will flag most of these for you.

The practical takeaway

A DMARC record is a small contract written in DNS, and now you can read every clause of it. The version and policy tags do the load-bearing work, the alignment tags (adkim, aspf) decide how forgiving the checks are, and the reporting tags (rua above all) give you the visibility to move safely from monitoring to enforcement. Most of the remaining tags either repeat their own defaults or address forensic reporting that few providers still send, so a good record stays short and sets only what it needs to.

The hard part was never the syntax. It is knowing your record is safe to advance from p=none to p=reject without dropping a single legitimate message, and that judgement comes from reading your reports correctly over time. If you would like to see your current record parsed tag by tag, start with the free DMARC checker or browse the full set of diagnostic tools. And if you would rather have the whole journey to enforcement handled for you, with monitoring and change alerts built in, that is exactly what the hosted DMARC Engine service is built to do.

Share

See where your domain stands today

Run a free DMARC scan, then let us take you to enforced p=reject with no email outage.