Who this is for. Whoever is about to publish, tighten or troubleshoot a DMARC policy for a small or mid-sized organisation. It assumes SPF and DKIM already exist and are understood; if they are not, start with how SPF and DKIM are checked.
DMARC is the policy layer: it decides what a receiver should do when a message fails to align with the domain people see in the From line, and it reports back what is happening. It is also the control most often switched to enforcement too early. This guide explains alignment, the policy values, mailing lists and forwarding, and gives a rollout order that finds legitimate senders before it blocks anything.
DMARC: alignment and policy
DMARC is a TXT record published at _dmarc.<your domain>. It does two jobs: it tells receivers what to do when a message fails, and it asks them to send you reports about what they saw.
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com"
How a message passes
A message passes DMARC if at least one of these is true:
- SPF passed, and the envelope sender domain is aligned with the From domain.
- DKIM passed, and the
d=domain is aligned with the From domain.
Alignment has two modes, set separately for SPF (aspf) and DKIM (adkim). The default for both is relaxed.
| Mode | Rule | Example: From is news.example.com |
|---|---|---|
Relaxed (r) | The two domains share the same organisational domain | Signing as example.com or mail.example.com aligns |
Strict (s) | The domains must match exactly | Only news.example.com aligns |
Relaxed alignment is right for nearly everyone. Strict alignment can break legitimate mail from subdomains and buys little unless you have a specific reason.
The tags you will actually use
| Tag | Purpose |
|---|---|
v=DMARC1 | Required, first. |
p= | Policy for the domain: none, quarantine or reject. Required. |
sp= | Policy for subdomains. If absent, subdomains inherit p. |
rua= | Where to send aggregate reports, as mailto: addresses. |
ruf= | Where to send failure reports. Few receivers send these, and they can contain message content, so think before you ask. |
pct= | Apply the policy to only this percentage of failing mail. Useful while ramping up. |
adkim= / aspf= | Alignment mode, r or s. |
If the report mailbox is on a different domain from the one the record protects, that other domain must publish a record authorising it, or many receivers will not send reports there.
Rolling out a policy without an outage
p=none blocks nothing. It exists so you can collect reports and learn who is really sending mail as you. The safe progression:
- Monitor. Publish
p=nonewithrua. Collect for long enough to see the quiet senders: the monthly invoice run, the quarterly statement system, the annual renewal notice. A couple of weeks is rarely enough. - Fix. For every legitimate source that fails, either authorise it in SPF, set up DKIM signing aligned to your domain, or retire it.
- Quarantine, gradually. Move to
p=quarantine, optionally withpct=10then higher, and watch reports and complaints. - Reject. Move to
p=rejectwhen the reports show your legitimate mail aligning. Keep monitoring afterwards; a new SaaS tool arrives every few months.
; stage 1
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com"
; stage 3
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; pct=25; rua=mailto:dmarc-reports@example.com"
; stage 4
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc-reports@example.com"
What an aggregate report tells you
Aggregate reports are XML, usually compressed, sent roughly daily by each receiver that supports it. Each report lists source IP addresses, how many messages came from each, and how SPF, DKIM and the DMARC disposition turned out. A cut-down record looks like this:
<record>
<row>
<source_ip>198.51.100.77</source_ip>
<count>412</count>
<policy_evaluated><disposition>none</disposition><dkim>fail</dkim><spf>fail</spf></policy_evaluated>
</row>
<identifiers><header_from>example.com</header_from></identifiers>
<auth_results>
<spf><domain>bounce.vendor-mail.example</domain><result>pass</result></spf>
</auth_results>
</record>
Four hundred and twelve messages from one address, passing SPF for the vendor’s domain but failing alignment for yours. Either that address is a service you use and have not finished setting up, or it is somebody else. Raw XML is not pleasant to read, which is why most organisations send reports to a processing service or a tool rather than a person’s inbox.
Subdomains and domains that never send
An attacker does not need your main domain; billing.example.com or a forgotten parked domain will do if either has no policy. The sp= tag covers subdomains in one line. For domains that should never send mail at all, publish the strictest possible statement:
parked.example. IN TXT "v=spf1 -all"
_dmarc.parked.example. IN TXT "v=DMARC1; p=reject;"
parked.example. IN MX 0 .
The final line is a “null MX” (RFC 7505), stating the domain does not accept mail.
Mailing lists, forwarding and ARC
Forwarding and mailing lists are the two legitimate things that break authentication. Forwarding breaks SPF. Lists often modify the subject or footer, which breaks DKIM. DMARC passes if either aligns, so forwarded mail usually survives through its DKIM signature, and list mail is the harder case. Receivers increasingly use ARC (RFC 8617), which lets an intermediary vouch for the results it saw. You cannot configure your way out of this from the sender’s side; it is one more reason to move to enforcement gradually and read the reports.
Brief notes on neighbouring standards
MTA-STS and TLS-RPT. SPF, DKIM and DMARC protect against forged mail. They do not protect the connection. MTA-STS (RFC 8461) lets you publish a policy, over HTTPS at a well-known path on an mta-sts host plus a TXT record, that tells sending servers to require TLS to your mail servers and which names to expect; modes include testing and enforce. TLS-RPT (RFC 8460) is the matching reporting channel, a TXT record at _smtp._tls. These are worth doing after authentication is stable, and they carry the same discipline: start in testing mode and read the reports.
BIMI. BIMI shows a brand logo beside authenticated mail. It depends on an enforcing DMARC policy, and whether and how a logo is displayed depends on each mailbox provider’s own requirements, which can include certificates. Treat it as a later, optional step and read each provider’s current requirements before investing in it.
The checklist, in order
This list is general. Tick items only after you have checked them with your own DNS tools and mail platform. A checklist you have read is not a configuration you have verified.
- List every system that sends mail with your domain in the From address. Include invoicing, CRM, marketing, helpdesk, scanners, website forms and monitoring alerts.
- For each, note the envelope domain it uses and whether it can sign DKIM under your domain.
- Publish one SPF record at the root of each sending domain, with every legitimate source in it, ending
~allfor now. - Count lookups recursively and confirm the total is 10 or fewer, with margin.
- Enable DKIM signing on the main mail platform. Use 2048-bit keys where supported. Record the selector.
- Enable DKIM signing, aligned to your domain, on each third-party sender.
- Publish DMARC at
p=nonewith aruaaddress that something will actually process. - Review reports for several weeks. Fix or retire every legitimate source that fails alignment.
- Move to
p=quarantine, optionally with a lowpct, then raise it. - Move to
p=reject. Setsp=if subdomains need a different policy. - Publish
v=spf1 -all, a reject DMARC policy and a null MX on every domain that never sends. - Put a recurring reminder in the calendar: review senders, rotate DKIM keys, and re-read reports.
How this fails
- Two SPF records. Added “just for this vendor”. SPF becomes a permanent error for the whole domain.
- Over 10 lookups, noticed late. A new include pushes the total past the limit, SPF starts failing intermittently depending on which branch is evaluated, and nobody connects it to the DNS change.
- Enforcing too early.
p=rejectpublished after a few days of reports, then the monthly statement run fails. The fix is patience, not a more clever record. - Third-party mail that passes its own checks. The vendor’s SPF and DKIM pass; yours do not align. DMARC fails, and the vendor’s support says everything is configured correctly, because by their standard it is.
- A 2048-bit key that will not save. The record is over 255 characters in one string, or the base64 was damaged by line breaks or pasted spaces.
- Reports sent to a mailbox nobody reads. You have the data and none of the benefit.
- Forgetting subdomains and parked domains. The attacker uses the one you did not publish a policy for.
What to do next
If a failing check turns out to be SPF or DKIM, go back to how SPF and DKIM are checked. Work out where you stand with the email security readiness assessment, which includes a browser-only explainer for SPF and DMARC text you paste in. Then read Microsoft 365 security for the tenant-side settings that sit beside these DNS records, and phishing protection for the attacks that DMARC cannot stop, such as lookalike domains and display-name tricks.