Learn

DMARC by example

Four worked scenarios with real DNS records and Authentication-Results headers. Each one ends with a one-line diagnosis and the fix, so you can match what you see on your own outbound mail against a known-good reading.

Last updated July 2026

This is the companion to SPF, DKIM & DMARC explained. That page covers what each check proves and how alignment ties them to the visible From: domain; this one assumes you already know that and walks through concrete cases. If a term like alignment or envelope sender is unfamiliar, start there first.

Throughout, the sending domain is example.com and the receiver’s verdict is read from the Authentication-Results header it stamps on the message. The single rule to keep in mind: DMARC passes when at least one of SPF or DKIM both passes and is aligned with the From: domain.

1. A clean pass

Everything lines up: SPF passes on a Return-Path in the same domain, DKIM passes with a matching d=, and both are aligned to the From: domain. The published DMARC record:

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

The relevant message headers the receiver evaluated:

From: no-reply@example.com
Return-Path: <bounces@example.com>
DKIM-Signature: v=1; a=rsa-sha256; d=example.com; s=mail2026; h=from:to:subject:date; ...

And what it recorded:

Authentication-Results: mx.receiver.com;
  spf=pass smtp.mailfrom=example.com;
  dkim=pass header.d=example.com header.s=mail2026;
  dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=example.com
Diagnosis: pass

SPF passes and its smtp.mailfrom domain matches header.from; DKIM passes and its d= matches too. Either one alone would satisfy DMARC — having both is the resilient state you want, since DKIM survives forwarding while SPF does not. No fix needed. This is the reading to compare every other case against.

2. DKIM passes but isn’t aligned

The classic failure. You send through an email provider that signs every message with its own domain rather than yours. The signature is cryptographically valid — dkim=pass — but the d= domain is not your From: domain, so it doesn’t count for DMARC. If SPF is also unaligned (common when the provider owns the Return-Path), DMARC fails outright.

From: no-reply@example.com
Return-Path: <bounce@mail.your-esp.net>
DKIM-Signature: v=1; a=rsa-sha256; d=your-esp.net; s=s1; h=from:to:subject; ...
Authentication-Results: mx.receiver.com;
  spf=pass smtp.mailfrom=mail.your-esp.net;
  dkim=pass header.d=your-esp.net header.s=s1;
  dmarc=fail (p=REJECT dis=REJECT) header.from=example.com
Diagnosis: fail — no aligned identifier

Both checks say pass, which is why this one fools people. But spf=pass authenticated mail.your-esp.net and dkim=pass authenticated your-esp.net — neither is aligned with header.from=example.com, so DMARC has nothing valid and aligned to accept. Under p=reject the message is refused.

Fix: configure the provider to sign with your domain. You publish their public key under a selector on your DNS (e.g. s1._domainkey.example.com) so the signature can carry d=example.com. After the change the header reads dkim=pass header.d=example.com and dmarc=pass — even though SPF is still unaligned, because one aligned pass is enough.

3. SPF passes, but on the wrong domain

SPF authenticates the Return-Path, not the From:. When your provider uses a bounce domain that is a subdomain of yours, relaxed alignment (the default) still passes because both share the organizational domain example.com:

From: no-reply@example.com
Return-Path: <bounce@bounces.example.com>
Authentication-Results: mx.receiver.com;
  spf=pass smtp.mailfrom=bounces.example.com;
  dmarc=pass (p=REJECT) header.from=example.com  # relaxed SPF alignment
Diagnosis: pass under relaxed alignment

bounces.example.com and example.com share the same organizational domain, so relaxed SPF alignment is satisfied and DMARC passes on SPF alone.

Now the pitfall. If your DMARC record sets aspf=s (strict SPF alignment), the Return-Path domain must match the From: domain exactly — a subdomain no longer counts:

_dmarc.example.com.  IN TXT  "v=DMARC1; p=reject; aspf=s; adkim=s; rua=mailto:dmarc@example.com"
Authentication-Results: mx.receiver.com;
  spf=pass smtp.mailfrom=bounces.example.com;
  dmarc=fail (p=REJECT) header.from=example.com  # aspf=s: bounces.example.com != example.com
Diagnosis: fail — strict alignment too tight

SPF still passes, but under aspf=s the exact-match requirement rejects the subdomain Return-Path, so the SPF identifier no longer aligns. Unless an aligned DKIM signature also covers this mail, DMARC fails.

Fix: drop aspf=s back to relaxed (omit it — relaxed is the default) unless you genuinely need exact-match SPF and control the Return-Path to sit on the bare domain. Strict alignment is a deliberate hardening step, not a default to reach for; most senders using a provider’s bounce subdomain want relaxed.

4. Reading a p=none quarantinereject rollout

You never jump straight to p=reject. The safe rollout is a staged tightening, using aggregate (rua) reports to confirm every legitimate source authenticates before you start dropping mail. Start in monitor-only mode:

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

Under p=none, receivers take no action on failures but still send you daily XML aggregate reports to the rua address. Each report summarizes, per source IP, how your mail authenticated. A row in one such report:

<record>
  <row>
    <source_ip>203.0.113.9</source_ip>
    <count>128</count>
    <policy_evaluated>
      <disposition>none</disposition>
      <dkim>fail</dkim>
      <spf>fail</spf>
    </policy_evaluated>
  </row>
  <identifiers><header_from>example.com</header_from></identifiers>
</record>
Diagnosis: an unaligned source, not yet dropped

128 messages from 203.0.113.9 claim to be from example.com but fail both DKIM and SPF alignment. It is either a forgotten legitimate sender (a billing system, a marketing tool) or a spoofer. disposition=none means nothing was dropped — this is exactly what monitoring is for.

Fix: identify the source. If it is yours, bring it into alignment (sign with your domain, or add it to SPF). Once reports show only aligned passes, tighten in steps — quarantine with pct to ramp exposure, then full reject:

# Stage 2 — quarantine a slice, keep watching reports
"v=DMARC1; p=quarantine; pct=25; rua=mailto:dmarc@example.com"

# Stage 3 — enforce once reports are clean
"v=DMARC1; p=reject; rua=mailto:dmarc@example.com"

The pct tag applies the policy to that percentage of failing mail (here, 25% quarantined, the rest treated as none), letting you widen enforcement gradually. Note that pct only degrades toward the next-lower action — it is a rollout lever, not a way to enforce a fraction of a reject.

Seeing these on your own outbound

Aggregate reports tell you what happened yesterday, in bulk. When you are actively fixing a signing or alignment problem you want the per-message reading now. Point your app’s signup, OTP or password-reset mail at a private, persistent Perenmail address and open the message: the raw source & header view surfaces synthesized SPF, DKIM and DMARC auth results alongside the full RFC822 source — the actual DKIM-Signature, Return-Path and From: headers — so you can confirm a fix landed before it reaches a real recipient. Raw source, headers and attachments are part of Personal+.

Because the inbox is persistent and tied to your signed-in account, you can keep a dedicated address per project and re-run the same test after each DNS change without losing history.

Keep reading

Read DMARC results on your own mail

Send your app’s outbound to a private, persistent Perenmail address and check the synthesized auth results per message. Free to start, no credit card.