← Email SecurityEmail Auth / Policy

DMARC — Domain-based Message Auth, Reporting & Conformance

The policy layer that ties SPF and DKIM together — telling receivers what to do with unauthenticated email and giving you visibility into who is sending on your behalf.

How It Works

Policy, Alignment, and Reporting

DMARC builds on SPF and DKIM by adding two things: alignment and policy. Alignment means the authenticated domain (from SPF or DKIM) must match the header From domain that users see. Policy tells receiving servers what to do when a message fails alignment — none, quarantine, or reject.

DMARC is published as a DNS TXT record at _dmarc.example.com. It references SPF and DKIM results, checks alignment, and — critically — enables aggregate reports (daily XML summaries) and forensic reports (per-failure samples) sent to addresses you specify. These reports are the most valuable output of DMARC: they reveal who is sending email using your domain before you ever enforce policy.

A message passes DMARC if at least one of SPF or DKIM passes and is in alignment with the header From. A message can fail SPF (due to forwarding) but pass DMARC via DKIM alignment — or fail DKIM but pass via SPF alignment.

DMARC Closes SPF's GapSPF authenticates the envelope From (MAIL FROM), which is invisible to end users. An attacker can pass SPF for their own domain while spoofing the visible From header. DMARC alignment requires the SPF-authenticated domain to match the header From — closing this spoofing gap.
; DMARC record anatomy _dmarc.example.com. IN TXT "v=DMARC1; p=reject; ; policy: reject failing mail sp=quarantine; ; subdomain policy pct=100; ; apply to 100% of messages adkim=r; ; DKIM alignment: relaxed aspf=r; ; SPF alignment: relaxed rua=mailto:dmarc-agg@example.com; ruf=mailto:dmarc-fail@example.com; fo=1" ; report on any failure
Policy

Policy Modes: none, quarantine, reject

p=none — Monitor mode

No action is taken on failing messages — they are delivered normally. Reports are still generated and sent. This is the starting point for every new DMARC deployment. Use p=none for weeks or months to collect aggregate reports, identify all legitimate sending sources, and ensure SPF/DKIM are properly configured before enforcing.

Start here. Never publish p=reject before reviewing aggregate reports.
p=quarantine — Soft enforcement

Failing messages are placed in the spam/junk folder rather than being rejected. A useful intermediate step between none and reject — it enforces policy without causing delivery failures that could affect legitimate mail you haven't yet identified. Use pct= to apply quarantine to only a percentage of failing mail during rollout.

Move here after verifying all legitimate senders pass DMARC.
p=reject — Full enforcement

Receiving servers reject failing messages outright — they never reach the inbox. This is the target state for all domains. Once at p=reject, spoofed email using your domain is blocked at the perimeter of the receiving mail system. Required by PCI-DSS 4.0 (March 2025) and recommended by CISA for government domains.

Goal state. Protects your domain from spoofing and phishing.
pct= — Gradual rollout

The pct= tag applies the enforcement policy to only a percentage of failing messages (default: 100). Setting pct=10 means only 10% of failing messages are quarantined or rejected; the rest are treated as p=none. Use this to gradually increase enforcement and confirm no legitimate mail is affected.

Use pct=10, 25, 50, 100 when stepping from none → quarantine → reject.
Alignment

Relaxed vs. Strict Alignment

Alignment compares the header From domain against the domain authenticated by SPF (envelope From) or DKIM (d= tag). There are two modes:

Relaxed alignment (adkim=r / aspf=r) — the authenticated domain and the header From domain must share the same organizational domain (registered domain + TLD). Example: DKIM signed with mail.example.com is in relaxed alignment with From: user@example.com. This is the default and recommended for most organizations.

Strict alignment (adkim=s / aspf=s) — the authenticated domain and the header From domain must match exactly. A subdomain mailing on behalf of the parent domain will fail strict alignment. Use strict only when you have complete control over all sending infrastructure.

; Alignment examples ; RELAXED alignment (adkim=r, default) ; Header From: user@example.com ; DKIM d= tag: mail.example.com ; Org domain: example.com (both) ; Result: ALIGNED ✓ ; STRICT alignment (adkim=s) ; Header From: user@example.com ; DKIM d= tag: mail.example.com ; Result: NOT ALIGNED ✗ ; (exact match required) ; SPF alignment (aspf=r, relaxed) ; Header From: user@example.com ; Envelope From: bounce@mail.example.com ; Org domain: example.com (both) ; Result: ALIGNED ✓
Visibility

Reading DMARC Aggregate Reports

Aggregate reports (RUA) are sent daily by receiving mail systems as XML files, one per reporting organization. Each report covers a 24-hour period and lists: source IP, message count, SPF and DKIM pass/fail, alignment pass/fail, and the applied disposition. They are invaluable for discovering shadow IT senders, misconfigured ESPs, and spoofing attempts.

Raw XML is readable but unwieldy. Use a DMARC reporting service to aggregate, parse, and visualize reports across all your domains. Major services include dmarcian, Valimail, Proofpoint Email Fraud Defense, and free options like Google Postmaster Tools (for gmail.com traffic) and parsedmarc (open source).

  • rua= receives daily aggregate XML reports (gzip attachment)
  • ruf= receives per-failure forensic reports (actual message samples — privacy-sensitive)
  • fo=0: report if all mechanisms fail (default) | fo=1: report on any failure
  • Reports from Google, Yahoo, Microsoft cover the majority of consumer email traffic
  • Cross-domain reporting: use mailto:dmarc@reports.example.com and publish a verification record at the receiving domain to confirm consent
<!-- DMARC aggregate report (simplified XML) --> <feedback> <report_metadata> <org_name>google.com</org_name> <date_range> <begin>1704067200</begin> <end>1704153600</end> </date_range> </report_metadata> <policy_published> <domain>example.com</domain> <p>reject</p> <adkim>r</adkim> <aspf>r</aspf> </policy_published> <record> <row> <source_ip>209.85.220.41</source_ip> <!-- legitimate --> <count>1243</count> <policy_evaluated> <disposition>none</disposition> <dkim>pass</dkim> <spf>pass</spf> </policy_evaluated> </row> </record> <record> <row> <source_ip>45.33.32.156</source_ip> <!-- spoofing attempt --> <count>12</count> <policy_evaluated> <disposition>reject</disposition> <dkim>fail</dkim> <spf>fail</spf> </policy_evaluated> </row> </record> </feedback>
Implementation

The Journey to p=reject

1

Publish p=none with reporting addresses

Start collecting aggregate reports without any enforcement. Use rua= to receive daily XMLs. Set a low TTL (300s) for easy future changes. Give this at least 2–4 weeks to collect data from major mailbox providers.

2

Audit all sending sources

Review aggregate reports to identify every IP and mail system sending email on behalf of your domain. Common surprises: old marketing platforms, partner integrations, development systems sending alerts, acquisition-era domains.

3

Ensure all legitimate senders have SPF and DKIM

Add each legitimate sender to your SPF record. Verify DKIM is configured for each mail system. Confirm alignment passes in aggregate reports — each sender should show 100% DMARC pass rate.

4

Move to p=quarantine with pct=10

Begin gradual enforcement. Start at pct=10 to verify no legitimate mail is caught. Monitor reports for any new DMARC failures appearing after quarantine begins. Step up: 25%, 50%, 100%.

5

Promote to p=reject

Once quarantine at pct=100 shows no legitimate mail failing DMARC, switch to p=reject. This is the goal: phishing and spoofing attempts using your domain are rejected at the receiving server before reaching inboxes.

Diagnostics

Inspecting and Testing DMARC

Look up DMARC record

# Query DMARC TXT record dig TXT _dmarc.example.com +short # Check subdomain policy separately # (sp= tag in _dmarc.example.com) # If no sp=, subdomain inherits p= # Check organizational domain record dig TXT _dmarc.company.example.com +short

Validate full email auth stack

# checkdmarc — comprehensive validator pip install checkdmarc checkdmarc example.com # Checks: SPF, DKIM selectors, # DMARC policy, BIMI, MTA-STS # Outputs JSON report

Simulate DMARC evaluation

# Send test email to Gmail # Check Authentication-Results header: Authentication-Results: mx.google.com; dkim=pass header.i=@example.com; spf=pass smtp.mailfrom=example.com; dmarc=pass (p=REJECT) header.from=example.com; # Or use: mail-tester.com, learndmarc.com

Parse aggregate reports

# parsedmarc — open source CLI tool pip install parsedmarc # Parse a report XML file parsedmarc -n report.xml # Or parse from email inbox parsedmarc --imap-host mail.example.com \ -u user -p pass \ --imap-folder DMARC