Practical engineering guidance
SPF, DKIM and DMARC as an operational sequence
Three DNS records that only work in a specific order. Publishing a strict DMARC policy before the inventory is complete is how organisations stop their own invoices arriving.
Series: Exchange and Microsoft 365
Email authentication is three records that answer three different questions, and they only produce a useful result when combined in the right order. Almost every failure I have seen came from doing them in the wrong one — usually publishing a rejecting DMARC policy before knowing who legitimately sends as the domain.
The order matters more than the syntax, so this article is organised around the sequence.
Requirements: what each record actually does
SPF answers: is this server allowed to send for this domain? It is a TXT record listing
authorised sending sources, checked against the envelope sender — the 5321.MailFrom
address, not the address the recipient sees.
DKIM answers: was this message signed by the domain, and is it unmodified? The sending system signs headers and body with a private key; the public key is published in DNS under a selector. A valid signature proves origin and integrity, and unlike SPF it survives a straightforward forward.
DMARC answers: what should the recipient do when the visible From address is not
backed up by an aligned, passing SPF or DKIM result? It is the policy layer, and it is the
only one of the three that protects the address users actually see — the 5322.From header.
That last distinction is the point of the whole exercise. SPF and DKIM on their own validate things the recipient never looks at. DMARC ties them to the visible sender through alignment:
- DMARC passes via SPF when the
5321.MailFromdomain aligns with the5322.Fromdomain. - DMARC passes via DKIM when the DKIM signing domain aligns with the
5322.Fromdomain.
Only one needs to pass. But alignment is required, which is why a domain with a passing SPF record can still fail DMARC — the sending service authenticated its own domain, not yours.
Step one: the inventory, which is the actual work
Before publishing anything, list every system that sends email using your domain in the visible From address. This is where the project succeeds or fails, and it always takes longer than the DNS work.
The list normally includes, and is rarely limited to:
- Microsoft 365 itself.
- Marketing and newsletter platforms.
- The finance system sending invoices and remittances.
- The HR and payroll systems.
- Ticketing and service desk tools.
- Monitoring and alerting systems.
- Multifunction devices that scan to email.
- Applications relaying through an on-premises Exchange server.
- Anything a department signed up for without telling you.
That last category is why the inventory cannot be built from a document. It has to be built from evidence, and DMARC’s own reporting is the best source of it — which is why the sequence starts with a monitoring-only policy rather than ending with one.
Step two: SPF, published carefully
Publish one SPF record per domain. Exactly one — multiple SPF TXT records is a permanent error condition, not a merge.
v=spf1 include:spf.protection.outlook.com include:_spf.example-service.com -all
Two constraints decide most SPF problems:
The ten DNS lookup limit. Each include, a, mx, ptr and exists mechanism costs
lookups, and nested includes count too. Exceed ten and the evaluation returns a permanent
error, which typically means DMARC cannot pass via SPF at all. Large organisations hit this
routinely, and the answer is consolidation or an SPF flattening service — not another
include.
The final mechanism. -all is a hard fail; ~all is a soft fail. Start with ~all
while you are still discovering senders, and move to -all once the inventory is stable.
Going straight to -all on an incomplete inventory produces exactly the outage this article
exists to prevent.
SPF does not survive most forwarding, because the forwarding server becomes the sender. That is not a fault in your configuration — it is why DKIM matters.
Step three: DKIM, enabled and rotated
For Microsoft 365, enable DKIM signing per custom domain and publish the two CNAME records
for selector1 and selector2. The two selectors exist so that key rotation can happen
without an interruption: signing moves between them.
Points worth attention:
- Enable it for every custom domain you send from, not just the primary. An unsigned subdomain is a gap.
- Third-party senders need their own DKIM setup, signing with your domain. A service that signs with its own domain gives you nothing for DMARC alignment, and this is the most common reason a well-configured domain still fails DMARC for one particular sender.
- Rotate keys. Microsoft 365 handles rotation for its own signing; anything you operate yourself needs a rotation schedule with an owner.
Step four: DMARC, in three stages
This is the part that must be staged. Publish at _dmarc.contoso.com.
Stage one — monitor. Publish p=none with an aggregate reporting address:
v=DMARC1; p=none; rua=mailto:dmarc-reports@contoso.com; fo=1
p=none asks recipients to take no action and send reports. Nothing changes for your mail
flow, and within days you begin receiving aggregate reports naming every source sending as
your domain. This is how the inventory gets completed.
Use a dedicated mailbox or a reporting service. Raw aggregate reports are XML, and at any scale they need parsing rather than reading.
Stage two — quarantine, with a percentage. Once the reports show your legitimate senders
authenticating and aligning, move to quarantine — and use pct to phase it:
v=DMARC1; p=quarantine; pct=25; rua=mailto:dmarc-reports@contoso.com
Raise the percentage as confidence grows. Watch the reports at each step, not just the service desk.
Stage three — reject. Only when the reports are clean:
v=DMARC1; p=reject; rua=mailto:dmarc-reports@contoso.com
Consider sp= for subdomain policy, and publish a restrictive record on domains you own but
never send from — a parked domain with p=reject and an SPF record of v=spf1 -all is a
cheap, complete win.
Why this is no longer optional
The large consumer mail providers now require authentication from high-volume senders rather
than merely preferring it. Microsoft defines a high-volume sender as one sending 5,000 or
more messages to its consumer mail services using the same domain in the 5322.From address,
and requires SPF, DKIM and a valid DMARC record for those domains.
Two details in that requirement catch people out:
- The threshold is sticky. Once a domain has crossed it, the requirements apply even if the daily volume later falls below 5,000.
- Enforcement is per message. An individual message that does not meet the requirements can be rejected even though other messages from the same domain pass.
Confirm the current thresholds and requirements at the time you plan the work — this is an area the providers have been changing.
Validation
Check the records resolve and parse before trusting them:
Resolve-DnsName -Type TXT -Name contoso.com
Resolve-DnsName -Type TXT -Name _dmarc.contoso.com
Resolve-DnsName -Type CNAME -Name selector1._domainkey.contoso.com
Then validate behaviour rather than syntax:
- Send from each inventoried system to a mailbox you control at a different provider, and
read the authentication results in the message headers.
spf=pass,dkim=passanddmarc=pass— and check that DMARC passed through alignment, not that SPF merely passed. - Read the aggregate reports for at least a full month before tightening the policy. Monthly processes send email too.
- Confirm your SPF record is under the lookup limit using a checker, and re-check after any vendor change — a provider altering their own include can push you over without you touching your record.
Where a message failed, the trace and the headers together give the answer. The approach in tracing a message through Exchange Online mail flow covers the Exchange Online side.
Operations
Forwarding will break SPF, and sometimes DKIM. Mailing lists that modify subject lines or add footers break DKIM signatures. ARC exists to let a trusted forwarder assert the original authentication result, and Microsoft 365 lets you designate trusted ARC sealers. Configure this where you have a legitimate forwarding relationship rather than weakening the policy.
Every new sending service is a change to this configuration. Put email authentication on the checklist for onboarding any service that will send as your domain. Without that, the inventory decays and someone eventually publishes a service that is rejected on day one.
Keep reading the reports after reaching p=reject. They are how you notice both a
legitimate sender breaking and somebody attempting to spoof you.
Rollback
Each stage is reversible by editing one TXT record, subject to DNS time-to-live. Keep the TTL low while you are moving through the stages so a rollback takes minutes rather than hours, and raise it once the policy is stable.
The irreversible part is the mail that was rejected while a policy was too strict. That is
the argument for the staged sequence and for pct, and it is the reason I would never move a
production domain straight to p=reject.
Verification and limits
SPF mechanics including the ten-lookup limit, DKIM selector-based rotation in Microsoft 365, DMARC policy values and alignment rules, and Microsoft’s high-volume sender requirements — including the 5,000-message definition, the sticky threshold and per-message enforcement — were checked against current Microsoft documentation on 20 September 2026.
No records were published or tested for this article. DNS changes to these records affect
whether your email is delivered: stage the DMARC policy, keep TTLs low during the transition,
and complete the sender inventory through p=none reporting before tightening anything.
References
Reader feedback
Was this article useful?
No ratings yet. Be the first to rate this article.
