DMARC Records Explained: Every Tag in the DNS Record (RFC 7489 + RFC 9091)

A tag-by-tag deep dive on the DMARC DNS record — every one of the twelve defined tags (v, p, sp, np, pct, rua, ruf, adkim, aspf, fo, rf, ri) with syntax, semantics, defaults, interaction rules, and worked examples. Covers RFC 7489, the np extension in RFC 9091, and the deprecations coming in draft-ietf-dmarc-dmarcbis.

This reference is provided in English. DMARC is specified in English-language RFCs (RFC 7489, RFC 9091) and the canonical tag syntax (v=DMARC1, p=reject, adkim=s, fo=1:d:s) does not translate. We keep the body in the source language so technical terms remain consistent with the specifications.

TL;DR

  • A DMARC record is a DNS TXT record at _dmarc.<domain> that tells receiving mail servers what to do with messages failing SPF and DKIM alignment, and where to send reports. Defined in RFC 7489, updated by RFC 9091 (the np tag) and the in-progress draft-ietf-dmarc-dmarcbis.
  • The record is a semicolon-separated list of tag=value pairs. Twelve tags are defined: v, p, sp, np, pct, rua, ruf, adkim, aspf, fo, rf, and ri.
  • Only v=DMARC1 and a p= value are required. Every other tag has an RFC-defined default. v= MUST be the first tag — anywhere else the record is malformed and ignored.
  • p governs the organizational domain; sp overrides it for existing subdomains without their own DMARC record; np covers non-existent subdomains (RFC 9091) — a spoofing vector neither p nor sp address.
  • adkim and aspf control identifier alignment: r (relaxed, default — match organizational domain) or s (strict — exact match).
  • rua is the aggregate-report destination (a mailto: URI); without it the feedback loop is silent. ruf is the forensic-report destination but is deprecated in dmarcbis.
  • Recommended production record: v=DMARC1; p=reject; sp=reject; np=reject; rua=mailto:dmarc@example.com; adkim=s; aspf=s; fo=1 — closes every spoofing vector and delivers actionable reports.

1. What is a DMARC record?

A DMARC record is a DNS TXT record published at the _dmarc subdomain of an email-sending domain. It carries the domain owner's authentication policy and reporting preferences in a compact, machine-readable format. DMARC itself is defined in RFC 7489 — Domain-based Message Authentication, Reporting, and Conformance (DMARC) (March 2015), with the np tag added in RFC 9091 (July 2021) and ongoing revisions in draft-ietf-dmarc-dmarcbis (the work-in-progress successor that obsoletes RFC 7489 when published).

Every DMARC record begins with the version tag v=DMARC1 and continues with one or more tag=value pairs separated by semicolons. A minimal monitoring-only record looks like this:

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=none; rua=mailto:dmarc@example.com"

A full enforcement record with subdomain and non-existent-subdomain coverage looks like this:

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=reject; sp=reject; np=reject;
                              rua=mailto:dmarc@example.com;
                              adkim=s; aspf=s; fo=1"

The record's job is purely to publish policy and reporting intent. The actual authentication decisions (does this message's SPF pass? does its DKIM signature verify? does the authenticated domain align with the From: header?) happen at the receiving mail server during message ingestion — DMARC merely tells the receiver what to do once those decisions are made.

For the broader DMARC primer (rollout strategy, aggregate-report XML format, mailing-list interactions), see help.php. This page is the deep dive on the record's tag-by-tag syntax — every published-but-rarely-explained tag with semantics, defaults, and worked examples.

2. How a receiver evaluates the record

  1. When mail arrives, the receiver extracts the From: header domain and computes its organizational domain (the registered name plus its public suffix — example.co.uk, not news.example.co.uk).
  2. The receiver queries DNS for _dmarc.<header-from> first; if no TXT record is found, it queries _dmarc.<organizational-domain>. This two-step lookup is why a subdomain without its own DMARC record inherits the organizational-domain policy.
  3. The TXT record is parsed left-to-right. v=DMARC1 MUST be the first tag — anywhere else and the record is treated as malformed and ignored. Per RFC 7489 §6.4, tag names are case-insensitive but values are case-sensitive in some positions.
  4. Each tag is validated against its allowed values. Unknown tags are ignored (forward compatibility); for a malformed value in a known tag the receiver falls back to the default or ignores that tag, and a record left without a valid policy tag is treated as monitoring-only if it names a valid report address, or else ignored (RFC 7489 §6.3 and §6.6.3).
  5. The receiver computes SPF and DKIM results independently, then applies identifier alignment using adkim and aspf to decide whether each authenticated identifier matches the From: header domain.
  6. If at least one of SPF-aligned or DKIM-aligned passes, the message passes DMARC and no policy is applied. If both fail, the receiver applies the policy chosen by the record (p, sp, or np depending on the subdomain situation).
  7. The receiver records the outcome and (once per configured reporting interval, default 24h) compiles an XML aggregate report to send to the rua= address.

3. DMARC DNS syntax

A DMARC record is a DNS TXT record at the _dmarc subdomain. Its RDATA is a quoted string of tag=value pairs separated by semicolons.

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=reject; rua=mailto:dmarc@example.com; sp=reject; adkim=s; aspf=s"
^                    ^   ^    ^                                                                              ^
|                    |   |    |                                                                              |
|                    |   |    +-- Quoted RDATA: semicolon-separated tag=value pairs                          |
|                    |   +------- Record type (TXT)                                                          |
|                    +----------- Class (IN)                                                                 |
+-------------------------------- Owner name — MUST be _dmarc.<domain>                                       |
                                                                                                             |
                                  v=DMARC1 MUST be first; remaining tags are order-independent.              |

Field-by-field anatomy:

Owner name
The record MUST be published at _dmarc.<domain> — the underscore prefix signals an "underscore label" per RFC 8552. Publishing at dmarc.example.com (no underscore) is a common mistake — the record is invisible to DMARC-aware receivers.
Record type
Always TXT. RFC 7489 §6.1 defines the DMARC record as a TXT record only; an SPF-type or any other record type is never read. A single quoted string is preferred; longer records that exceed the 255-byte single-string limit may be split into multiple quoted strings, which the receiver MUST concatenate (RFC 7489 §6.1); most DNS providers handle this automatically.
RDATA
A semicolon-separated list of tag=value pairs. v=DMARC1 MUST appear first; all other tags are order-independent but conventionally written in the order v, p, sp, np, pct, rua, ruf, adkim, aspf, fo, rf, ri.
Whitespace
Whitespace around = and between tags is permitted but not required. Most operators write v=DMARC1; p=reject; sp=reject (no spaces around =, single space after the semicolon). Trailing semicolons are permitted but unnecessary.

Only one DMARC record may be published per name. Two TXT records at _dmarc.example.com both starting with v=DMARC1 cause receivers to discard BOTH and treat the domain as having no DMARC policy at all — exactly the failure mode that duplicate publication is trying to avoid. Always consolidate to a single record.

4. Every DMARC tag, explained

RFC 7489 §6.3 defines eleven tags; RFC 9091 added the twelfth (np). Each tag has a well-defined default, so a minimal record omits most of them and relies on the defaults.

Tag Required? Default Allowed values Meaning
v Yes (and MUST be first) — DMARC1 Protocol version. The only defined value is DMARC1; future revisions will introduce DMARC2.
p Yes — none | quarantine | reject Policy applied to the organizational domain. none = monitor only, quarantine = deliver to spam, reject = bounce.
sp No Inherits p none | quarantine | reject Policy for EXISTING subdomains without their own DMARC record. Without sp, subdomains inherit p.
np No (RFC 9091) Inherits sp none | quarantine | reject Policy for NON-EXISTENT subdomains (NXDOMAIN). Covers a spoofing vector p and sp do not. Published in RFC 9091 (July 2021).
pct No 100 Integer 0-100 Percentage of failing messages the policy applies to. Deprecated in dmarcbis — receivers implement inconsistently.
rua No (none) Comma-separated mailto: URIs Aggregate-report destination(s). Without it the feedback loop is silent. May include a size limit: mailto:dmarc@example.com!10m.
ruf No (none) Comma-separated mailto: URIs Forensic-report destination(s). Deprecated in dmarcbis and rarely sent by receivers (privacy concerns).
adkim No r (relaxed) r | s DKIM alignment mode. r matches at organizational-domain level; s requires exact domain match.
aspf No r (relaxed) r | s SPF alignment mode. Same semantics as adkim but applied to the SPF-authenticated envelope domain.
fo No 0 0 | 1 | d | s (colon-combinable) Forensic-report generation conditions. 0 = both SPF and DKIM must fail. 1 = either fails. d = DKIM fails. s = SPF fails. Combine with colons: fo=1:d:s.
rf No afrf afrf Forensic-report format. The only RFC-defined value is afrf (Authentication Failure Reporting Format, RFC 6591). Effectively a no-op tag.
ri No 86400 Integer (seconds) Requested aggregate-report interval. 86400 = once per day. Receivers may honour shorter intervals but most send daily regardless.

Most production records contain six to eight tags. The minimum viable record is v=DMARC1; p=none; rua=mailto:…; the recommended hardened record adds sp, np, adkim=s, aspf=s, and fo=1.

5. How the tags interact

Several tags compose with each other in non-obvious ways. The interactions matter operationally because they determine which policy is actually applied to a given message.

p -> sp -> np precedence chain
The receiver picks ONE policy based on the From: header domain. (a) If the From: domain is the organizational domain itself, p applies. (b) If From: is an EXISTING subdomain (DNS resolves) without its own DMARC record, sp applies if published, else falls back to p. (c) If From: is a NON-EXISTENT subdomain (NXDOMAIN), np applies if published, else falls back to sp, else p. The np -> sp -> p waterfall is the explicit rule from RFC 9091 §2.
adkim + aspf independence
The two alignment modes are evaluated independently. A record with adkim=s; aspf=r applies strict alignment to DKIM and relaxed to SPF — useful when DKIM is signed by a tightly-controlled infrastructure but SPF includes a third-party sender on a sibling subdomain.
pct interaction with policy
pct=10; p=reject means "apply the policy of p=reject to 10% of failing messages; treat the remaining 90% as if the policy were one step less severe — quarantine". This downshift-not-skip behaviour is specified in RFC 7489 §6.6.4 and is still a frequent surprise. The deprecation in dmarcbis is in part because of this confusion.
fo requires ruf
fo only does anything when ruf= is also published — without a forensic-report destination there is nowhere for the receiver to send the generated reports. Publishing fo=1 alone is a no-op.
rua with size limits
Each mailto: URI in rua= can carry a size cap suffix: !10m means "reports up to 10 megabytes are welcome"; !100k caps at 100 kilobytes. Reports larger than the cap are NOT sent. Useful for protecting a small mailbox from a very large reporter.
Cross-domain report destinations
If the rua= or ruf= domain differs from the DMARC-record domain, the destination domain MUST publish an authorisation record at <source>._report._dmarc.<dest> containing v=DMARC1. See RFC 7489 §7.1. Without it the receiver refuses to send reports to the cross-domain address.

6. DMARC record examples

6.1 Minimal monitoring (Day 1)

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=none; rua=mailto:dmarc@example.com"

The starting point for every deployment. p=none tells receivers to take no action but still send aggregate reports. The record is safe to publish on day one — no legitimate mail will be impacted.

6.2 Soft enforcement (Phase 2)

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=quarantine; pct=25;
                              rua=mailto:dmarc@example.com"

Once monitoring has shown 95%+ alignment, move to quarantine with pct=25 to apply the policy to a quarter of failing messages. Raise pct gradually as alignment improves. Note: dmarcbis deprecates pct; use sub-week policy ramps instead.

6.3 Full enforcement with subdomain coverage

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=reject; sp=reject; np=reject;
                              rua=mailto:dmarc@example.com;
                              adkim=s; aspf=s; fo=1"

The recommended hardened record. p=reject stops spoofing of example.com itself; sp=reject covers existing subdomains without their own DMARC; np=reject covers non-existent-subdomain spoofing (fake.example.com when no such subdomain is in DNS); strict alignment on both DKIM and SPF; fo=1 requests forensic reports for either-fails cases.

6.4 Non-sending domain (parked)

_dmarc.example-parked.com.  IN  TXT  "v=DMARC1; p=reject; sp=reject; np=reject;
                                     rua=mailto:dmarc@example.com; aspf=s; adkim=s"

Domains that never send legitimate mail can go straight to p=reject on day one — there is no legitimate traffic to misclassify. Best practice for every brand-protection domain in a portfolio.

6.5 Forensic reports to a dedicated mailbox

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=reject;
                              rua=mailto:dmarc-rua@example.com!25m;
                              ruf=mailto:dmarc-ruf@example.com!10m;
                              fo=1:d:s"

Routes aggregate reports up to 25 MB to one mailbox and per-message forensic reports up to 10 MB to another. fo=1:d:s requests forensic reports for every failure type. Note most major receivers no longer send forensic reports for privacy reasons regardless of ruf=.

6.6 Cross-domain reporting

_dmarc.example.com.       IN  TXT  "v=DMARC1; p=reject;
                                  rua=mailto:reports@dmarc-vendor.com"

example.com._report._dmarc.dmarc-vendor.com.  IN  TXT  "v=DMARC1"

When the report destination is on a different domain than the DMARC record, the destination domain MUST publish an authorisation record per RFC 7489 §7.1. Most managed-DMARC vendors handle this for you when you onboard.

6.7 Multiple report destinations

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=reject;
                              rua=mailto:dmarc@example.com,
                                  mailto:reports@dmarc-vendor.com"

Reports get sent to BOTH addresses. Useful for running an internal dashboard while a managed vendor provides additional analytics. Each URI can carry its own size cap.

6.8 Faster reporting interval

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=reject;
                              rua=mailto:dmarc@example.com;
                              ri=3600"

Requests hourly aggregate reports (3600 seconds). Most major receivers ignore ri below the default 86400 seconds and still send daily reports — Google and Microsoft are explicit about this — but smaller receivers may honour the request. Use only when actively debugging.

7. DMARC record best practices

  • Always start with p=none and run for at least 4-8 weeks before any enforcement. Monitoring is what surfaces forgotten senders (marketing platforms, transactional services, helpdesk systems) before they get blocked.
  • Publish rua= on every DMARC record, even p=none ones. Without rua= there is no feedback loop and the record provides zero operational value.
  • Publish sp AND np explicitly — never rely on inheritance. Explicit beats implicit when a reader is auditing a record six months from now. np in particular is often forgotten because it only joined RFC 9091 in 2021.
  • Use adkim=s; aspf=s on non-sending domains. Strict alignment closes the relaxed-mode loophole that lets siblings of a subdomain pass DMARC when they should not.
  • Skip pct in new deployments. Dmarcbis deprecates it; receivers implement inconsistently; gradual policy ramping is better achieved with sub-week policy steps (none -> quarantine -> reject) than with partial application.
  • Set fo=1 when ruf= is published. fo=0 only reports when BOTH SPF and DKIM fail — exactly the cases that are easiest to diagnose anyway. fo=1 surfaces the partial-failure cases where the operational signal is highest.
  • Use a dedicated mailbox for rua reports. Daily XML attachments from every major receiver will flood a shared inbox. A dedicated dmarc@ mailbox (or, better, ingestion via IMAP / Microsoft Graph into a tool like DMARC Analyzer) keeps the feedback loop manageable.
  • Consolidate to a single TXT record at _dmarc.<domain>. Two records both starting with v=DMARC1 cause receivers to discard BOTH per RFC 7489 §6.6.3 — the domain effectively has no DMARC at all.
  • Audit the record after every DNS change. A typo in a tag value (v=DMARCv1, p=rejct) silently invalidates the record or reduces it to monitoring only. DMARC Analyzer's Domain Security Checker performs syntactic validation on every tag.
  • Watch for the v= first-position rule. p=reject; v=DMARC1; rua=... is ignored even though every individual tag is valid — v MUST be first.

8. Common DMARC record mistakes

  • Typo in v=DMARC1. Common variants — v=DMARCv1, v=DMARC.1, v=dmarc1 — invalidate the record. The literal value is exactly DMARC1 (uppercase), always.
  • Published at dmarc.example.com without the underscore. The owner name MUST be _dmarc.example.com (RFC 7489 §6.1). Underscore-less records are invisible to every receiver.
  • Two TXT records at _dmarc.<domain>. Receivers discard BOTH per RFC 7489 §6.6.3. A frequent failure when one team publishes a vendor's record and another adds an in-house record — always consolidate.
  • Forgetting the v=DMARC1 first-position rule. Some DNS UIs reorder tags alphabetically on save. Always verify with dig TXT _dmarc.<domain> after a DNS change.
  • Publishing p=reject without monitoring first. Almost guaranteed to bounce legitimate marketing or transactional mail until you discover and align every sender. Run p=none for at least one full reporting cycle (typically 4-8 weeks).
  • Missing or unreachable rua= mailbox. A DMARC record without a working report destination is publish-and-pray. Use a dedicated mailbox with at least 100 MB of free space; bounce-back from a full mailbox causes receivers to silently stop sending.
  • Cross-domain rua without authorisation record. If the report destination's domain differs from the DMARC-record domain, the destination MUST publish <source>._report._dmarc.<dest> IN TXT "v=DMARC1". Without it, no reports are sent.
  • Setting fo=1 without publishing ruf=. fo controls forensic-report generation but does nothing without a destination. Either publish both or publish neither.
  • Forgetting np entirely. np=reject is the strongest protection against subdomain-spoofing attacks that use non-existent subdomains (banking.example.com when no banking subdomain is in DNS). It only shipped in RFC 9091 (2021), so older records often lack it.
  • Using p=quarantine long-term as the "safe choice". Quarantine delivers spoofed mail to spam folders, where attackers know users actively rescue messages. Move to p=reject once stable.

9. DMARC record troubleshooting

The record exists but receivers act as if there is no DMARC policy
Three likely causes: (1) the record is at dmarc. instead of _dmarc. (no underscore); (2) v=DMARC1 is not in the first position; (3) two TXT records exist at _dmarc.<domain> both starting with v=DMARC1 — receivers discard duplicates per RFC 7489 §6.6.3. Verify with dig TXT _dmarc.<domain> +short.
Aggregate reports stopped arriving
Check (1) the rua= mailbox is not full; (2) the destination MX is reachable from the public internet; (3) any size-cap suffix (!10m) is large enough for the receiver's reports — Microsoft 365 reports routinely exceed 5 MB for high-volume domains; (4) the cross-domain authorisation record is still in place if applicable.
I see permerror as the DMARC result in the Authentication-Results header
The receiver could not parse your DMARC record. Common causes: extra unescaped quotes, smart-quote characters (curly instead of straight), or a tag value with invalid syntax (e.g. p=rejct with a typo). Re-publish a clean record and wait for the DNS TTL to expire.
Subdomain inheritance is not working
If news.example.com publishes its OWN DMARC record at _dmarc.news.example.com, it completely overrides the organizational-domain record — the sp tag is ONLY consulted when the subdomain has NO DMARC record. Decide whether each subdomain should have its own record or rely on sp; do not mix the two strategies.
Legitimate mail bounces after moving to p=reject
Revert to p=quarantine or p=none immediately to restore delivery; investigate which sender is unaligned via the next aggregate-report cycle. The pattern usually points at a forgotten SaaS sender that needs custom-domain DKIM enabled — see the DKIM deep dive for the per-platform procedure.
How do I see my published DMARC record?
Use dig TXT _dmarc.example.com +short from any modern dig install, or DMARC Analyzer's Domain Security Checker which parses every tag and flags missing required fields, weak policies, and unreachable report destinations.
The DMARC record looks right but DMARC results show none in reports
"none" in policy_evaluated.disposition means either (a) the message passed DMARC (one of SPF-aligned or DKIM-aligned passed) OR (b) your published policy is p=none. Check the policy_published.p field in the same report to disambiguate.

10. Frequently Asked Questions

What is a DMARC record?
A DMARC record is a DNS TXT record published at the _dmarc subdomain that tells receiving mail servers how to handle messages that fail SPF and DKIM alignment, where to send aggregate authentication reports, and which alignment mode (strict or relaxed) to apply. Defined in RFC 7489 and updated by RFC 9091 (np tag), the record is a semicolon-separated list of tag=value pairs starting with v=DMARC1. A typical record is: _dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com; sp=reject; adkim=s; aspf=s".
What are the required tags in a DMARC record?
Only two tags are strictly required: v (must be the literal v=DMARC1 and MUST be the first tag) and p (the policy — none, quarantine, or reject). Every other tag is optional and falls back to its RFC-defined default if omitted. Without rua= no aggregate reports are sent; without sp= the subdomain policy inherits p; without adkim/aspf the alignment mode defaults to relaxed.
What is the difference between the p, sp, and np tags?
p sets the policy for the organizational domain. sp (subdomain policy) overrides p for any existing subdomain that lacks its own DMARC record — without sp the subdomain inherits p. np (non-existent-subdomain policy, added by RFC 9091 in 2021) covers messages claiming to originate from a subdomain that does not exist in DNS at all — a common spoofing vector that p and sp do not address. Best practice: publish all three with reject for full coverage.
What does adkim=r vs adkim=s mean?
adkim and aspf control identifier alignment between the From: header domain and the DKIM signing domain (adkim) or SPF authenticated domain (aspf). r (relaxed, the default) requires the organizational domain to match — a DKIM signature on mail.example.com aligns with a From: of news@example.com. s (strict) requires an exact match — the same signature would NOT align with a different subdomain in From. Strict alignment is more secure; relaxed is more forgiving of cross-subdomain mail flows.
What is the pct tag and is it still recommended?
pct (percentage) tells receivers to apply the policy to only a percentage of failing messages — useful for staged rollout (pct=10, pct=50, pct=100). RFC 7489 defines it; however the in-progress dmarcbis draft (draft-ietf-dmarc-dmarcbis) deprecates pct because receivers implement it inconsistently and the testing benefit is small. Modern guidance: skip pct, ramp policy directly (none -> quarantine -> reject) and use sp/np for fine-grained control.
What does the fo tag do and which value should I use?
fo controls forensic-report generation conditions. fo=0 (default) reports only when BOTH SPF and DKIM fail. fo=1 reports when EITHER fails. fo=d reports when DKIM fails to verify regardless of alignment. fo=s reports when SPF fails. Multiple values can be combined with colons: fo=1:d:s. fo=1 is the standard production choice because it surfaces partial-failure cases that fo=0 hides; combine with ruf= to actually receive the reports.
How does DMARC Analyzer help me audit my DMARC record?
DMARC Analyzer's Domain Security Checker (domain_checker.php) performs a live DNS lookup for _dmarc.<your-domain> and parses every tag in the record, flagging missing required tags (v, p), weak policies (p=none after deployment), missing sp/np coverage, and report destinations that do not accept your domain. The DNS Record Generator (dns_generator.php) builds well-formed DMARC records with every tag validated against RFC 7489 / RFC 9091 syntax — copy the output directly into your DNS provider.

12. Audit your DMARC record now

DMARC Analyzer's Domain Security Checker performs a live DNS lookup for _dmarc.<your-domain> via includes/DnsChecker.php, parses every tag against the RFC 7489 + RFC 9091 grammar, and flags missing required tags (v, p), weak monitoring-only policies after enforcement deadlines, missing sp/np coverage, unreachable report destinations, and typographic errors that silently invalidate the whole record. The DNS Record Generator's DMARC wizard builds well-formed records with per-tag validation — copy the output directly into your DNS provider.

Check my DMARC record Sign up — Free plan