Email remains the single most abused entry point into organizations. According to the Verizon Data Breach Investigations Report, phishing and pretexting are involved in the majority of social-engineering breaches, and most of those start with a spoofed sender address. The three DNS-based authentication standards - SPF, DKIM and DMARC - exist to make spoofing your domain technically detectable and, at full enforcement, rejectable.
This guide is written for IT managers who need to take a real organization - with newsletters, a CRM, a helpdesk, invoicing software and a marketing platform all sending mail "from" the company domain - from zero email authentication to an enforced DMARC policy of p=reject, without losing a single legitimate message on the way. Expect the full rollout to take 6–10 weeks of calendar time, with only a few hours of hands-on work per week.
How the three protocols fit together
Before touching DNS, make sure the mental model is right, because most failed rollouts come from misunderstanding alignment.
- SPF (RFC 7208) publishes, in DNS, the list of IP addresses allowed to send mail using your domain in the SMTP envelope (MAIL FROM).
- DKIM (RFC 6376) cryptographically signs each message with a private key; the public key is published in DNS. Receivers verify the signature to confirm the message was not altered and was authorized by the signing domain.
- DMARC (RFC 7489) ties both together. It tells receivers: "if a message claims to be from my domain in the visible From: header, it must pass SPF or DKIM in alignment with that domain - and here is what to do if it does not, and here is where to send reports."
The verification flow at the receiving mail server looks like this:
Incoming message claiming From: billing@example.com
|
+------------------+------------------+
| |
SPF check DKIM check
Is sending IP listed in Does the d= signature
example.com's SPF record verify against the DNS
for the envelope sender? public key?
| |
+------------------+------------------+
|
DMARC alignment
Does the domain that passed (envelope domain for SPF,
d= domain for DKIM) match the visible From: domain?
|
+------------------+------------------+
| |
PASS: deliver FAIL: apply policy
p=none -> deliver, report
p=quarantine -> spam folder
p=reject -> refuse message
The crucial detail: a message can pass SPF and DKIM for some domain and still fail DMARC, because DMARC requires the passing domain to align with the From: header domain your users actually see. This is exactly what stops a phisher who signs mail with their own domain's DKIM key.
Phase 0 - Inventory every legitimate sender (week 1)
The number one cause of lost mail during DMARC rollouts is a forgotten sending service. Before publishing anything, build a sender inventory. Interview the marketing, sales, finance and HR teams, and check DNS for existing include: mechanisms.
Typical inventory for a 50-person company:
| Sending service | What it sends | Envelope domain | DKIM capable? |
|---|---|---|---|
| Google Workspace / M365 | Day-to-day corporate mail | example.com | Yes |
| Mailchimp / Brevo | Newsletters | mail.example.com | Yes (CNAME) |
| HubSpot / Pipedrive | Sales sequences | example.com | Yes |
| Zendesk / Freshdesk | Support replies | example.com | Yes |
| Fortnox / QuickBooks | Invoices | often their own domain | Varies |
| Website contact form | Notifications | web server IP | Usually no |
| Monitoring/CI (cron, Jenkins) | Alerts | server hostname | Usually no |
Two rules of thumb from this phase:
- Anything that cannot do DKIM should be migrated to send through an authenticated relay (e.g. your Workspace SMTP relay or a transactional provider such as Postmark or SES) rather than directly from a web server.
- Do not guess. The DMARC monitoring phase below will catch what interviews miss - that is what it is for.
Phase 1 - Publish a correct SPF record (week 1–2)
SPF is one TXT record on the root of your domain. Collect the include mechanisms from each provider's documentation and merge them into a single record - a domain must have exactly one SPF record; two records cause a permanent error (permerror) and effectively disable SPF.
example.com. IN TXT "v=spf1 include:_spf.google.com include:servers.mcsv.net include:_spf.hubspot.com ip4:203.0.113.25 ~all"
Key decisions:
- End with ~all (softfail), not -all, during rollout. DMARC does not need -all to work, and -all combined with an incomplete inventory bounces legitimate mail immediately. You can tighten to -all after monitoring confirms the inventory is complete.
- Stay under 10 DNS lookups. Every include, a, mx and redirect mechanism costs a lookup; exceeding ten is a permerror per RFC 7208 §4.6.4. Count the nested lookups inside each include (Google's include alone costs three). If you are near the limit, use SPF flattening cautiously or move bulk senders to a subdomain.
- Use ip4:/ip6: for servers you control instead of a: mechanisms - they cost no lookups.
Validate with a checker (FortifyNet's MX & email security tool shows SPF, DKIM and DMARC in one pass) and with dig:
dig +short TXT example.com | grep spf1
Phase 2 - Enable DKIM everywhere (week 2–3)
DKIM setup is per-provider, but always follows the same shape: the provider generates a key pair, you publish the public key at selector._domainkey.example.com, and the provider starts signing.
- Google Workspace: Admin console → Apps → Gmail → Authenticate email. Generate a 2048-bit key (1024-bit keys are considered weak; NIST and M3AAWG both recommend 2048). Publish the TXT record, wait for DNS propagation, click "Start authentication".
- Microsoft 365: Defender portal → Email authentication settings → DKIM. Microsoft uses two CNAME records (selector1, selector2) that enable automatic key rotation.
- Mailchimp, HubSpot, Zendesk etc.: each has an "authenticate your domain" wizard that gives you 2–4 CNAME records.
Verify each selector after publishing:
dig +short TXT google._domainkey.example.com
dig +short CNAME selector1._domainkey.example.com
Then send a test message to a Gmail address, open "Show original", and confirm you see DKIM: PASS with domain example.com - the "with domain" part is the alignment that DMARC will check.
Plan for key rotation every 6–12 months. Providers with CNAME-based setups rotate for you; for manually published keys, put a recurring calendar item on the security calendar now, because nobody remembers later.
Phase 3 - DMARC in monitoring mode (week 3–4)
Publish a DMARC record at _dmarc.example.com with policy p=none. This changes nothing about delivery - it only turns on reporting.
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com; fo=1; adkim=r; aspf=r"
What each tag does:
| Tag | Value | Meaning |
|---|---|---|
| p | none | Take no action on failures yet - just report |
| rua | mailto:… | Where daily aggregate (XML) reports are sent |
| fo | 1 | Generate a failure report if any mechanism fails |
| adkim / aspf | r | Relaxed alignment: subdomains of example.com count as aligned |
| sp | (unset) | Subdomain policy - inherit p for now |
Practical notes:
- Use a dedicated mailbox or, far better, a DMARC report processor - raw reports are gzipped XML and arrive from every large receiver daily. Free tiers of common analyzers are enough for a single domain.
- If the report address is on a different domain than the one being monitored, the report domain must publish an external destination verification record (RFC 7489 §7.1).
- Let monitoring run at least two full weeks, ideally four, so monthly jobs (invoice runs, board reports) appear in the data.
Phase 4 - Read the reports and fix what fails (week 4–6)
Aggregate reports answer three questions for every sending IP: how much mail, did SPF align, did DKIM align. Triage into three buckets:
- Aligned pass (SPF or DKIM): healthy. The bulk of your Workspace/M365 mail should be here from day one.
- Your service, failing alignment: e.g. the CRM passes DKIM but signs with d=crm-provider.com. Fix by completing that provider's domain authentication wizard so it signs with your domain. This bucket is your Phase 4 work queue.
- Unknown IPs failing everything: this is spoofing (or forwarding). You do not fix this - enforcement will neutralize it. Its presence is the business case for this whole project.
One legitimate source will keep failing no matter what you do: mailing lists and some forwarders break SPF (new sending IP) and sometimes DKIM (footer added). ARC (RFC 8617) helps at large receivers, but the honest answer is that a small residual failure rate (well under 1%) is normal and acceptable at enforcement.
Phase 5 - Ramp to enforcement (week 6–10)
Never jump from p=none straight to p=reject. Use the pct tag to ramp:
| Step | Record change | Hold time | Rollback trigger |
|---|---|---|---|
| 1 | p=quarantine; pct=10 | 1 week | any report of legitimate mail in spam |
| 2 | p=quarantine; pct=50 | 1 week | same |
| 3 | p=quarantine (pct=100) | 2 weeks | same |
| 4 | p=reject | permanent | aligned-pass rate drops below ~98% |
At each step, watch two signals: the aggregate reports (aligned-pass percentage for known senders should stay flat) and the helpdesk (tickets about "customer says my mail bounced"). Rollback is a single DNS change back to the previous step and takes effect within the record's TTL - set the TTL to 3600 seconds during the ramp so mistakes are cheap.
When you reach p=reject, finish the job:
- Add an explicit subdomain policy: sp=reject, unless a subdomain intentionally sends with looser rules.
- Protect parked domains you own but never send from: give each v=spf1 -all, an empty DKIM policy, and v=DMARC1; p=reject. Parked domains are the spoofer's favourite target.
- Consider BIMI (brand logo in inboxes) - it requires enforced DMARC, so you have just unlocked it.
Troubleshooting quick reference
| Symptom | Likely cause | Fix |
|---|---|---|
| permerror in reports | two SPF records, or >10 lookups | merge records; reduce includes |
| DKIM fail only at one receiver | DNS propagation or truncated TXT | re-check record; split 2048-bit key correctly across strings |
| Newsletter fails alignment | ESP signs with own domain | complete ESP domain authentication (CNAMEs) |
| Own web server mail rejected | form mail sent directly from web host | route through authenticated SMTP relay |
| Forwarded mail quarantined | forwarding breaks SPF | expected; rely on DKIM surviving, accept residual |
The rollout at a glance
| Week | Activity | Deliverable |
|---|---|---|
| 1 | Sender inventory interviews | signed-off sender table |
| 1–2 | SPF published and validated | one record, under 10 lookups |
| 2–3 | DKIM per provider, 2048-bit | PASS with aligned domain at Gmail test |
| 3–4 | DMARC p=none + report processor | reports flowing |
| 4–6 | Report triage, fix alignment gaps | bucket 2 empty |
| 6–10 | Ramp: q10 → q50 → q100 → reject | p=reject live, sp=reject set |
Print this table into the project ticket; each row is a natural weekly status update for management, and the deliverable column keeps the project honest about what "done" means at each step.
Beyond DMARC - MTA-STS and TLS-RPT
DMARC authenticates who sent a message; it says nothing about whether the message travelled encrypted. SMTP still falls back to plaintext when TLS negotiation fails, and an active attacker on the network path can force exactly that failure. Two companion standards close the gap, and since you are already in the DNS console this is the right week to deploy them.
MTA-STS (RFC 8461) lets your domain declare "only deliver mail to me over authenticated TLS". It consists of a DNS record and a small policy file served over HTTPS:
\`
_mta-sts.example.com. IN TXT "v=STSv1; id=20260828T000000"
https://mta-sts.example.com/.well-known/mta-sts.txt:
version: STSv1
mode: testing
mx: mail.example.com
max_age: 86400
`\
Run mode: testing for two weeks, then switch to mode: enforce and raise max_age to 604800. The mx lines must match your real MX hostnames exactly - a typo here silently drops inbound mail in enforce mode, which is why the testing stage exists.
TLS-RPT (RFC 8460) is the reporting channel for MTA-STS, exactly as rua reporting is for DMARC:
\
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:tls-reports@example.com"
\\
Senders that fail to deliver over TLS tell you why, daily, in machine-readable JSON. In practice the reports are quiet - which is precisely the confirmation you want before enforcing.
Reading an aggregate report by hand
Even with an analyzer, read one raw report once so the data stops being a black box. Inside the gzipped XML each record block contains three things that matter:
\
<record>
<row>
<source_ip>198.51.100.7</source_ip>
<count>412</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>fail</dkim>
<spf>pass</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>example.com</header_from>
</identifiers>
</record>
\\
Read it as a sentence: "198.51.100.7 sent 412 messages claiming to be example.com; SPF aligned, DKIM did not; under the current policy nothing was done." Look the IP up (reverse DNS plus the sender's published ranges) and you know whether this row is bucket 1, 2 or 3 from Phase 4. Ten minutes with one report teaches more than any dashboard tour.
Governance - keeping it enforced
Email authentication is not a project with an end date; it is a small standing capability. Bake these into normal operations before closing the ticket:
- Change control on DNS: every new SaaS tool that "just needs to send email as us" goes through you, gets DKIM set up properly, and is added to the inventory table. The alternative is that marketing signs up for a tool in November and its mail silently lands in spam under your p=reject.
- Quarterly report review: fifteen minutes per quarter scanning the analyzer for new failing sources. Calendar it.
- Monitoring the records themselves: SPF, DKIM and DMARC records can be broken by an innocent DNS migration. External monitoring that alerts on any change to these records - FortifyNet's domain monitoring does this continuously - turns a silent regression into a same-day fix.
- Offboarding: when a sending service is cancelled, remove its include and DKIM records the same week. Stale includes are both a lookup-budget leak and a supply-chain risk: if the provider's IP space is re-assigned, whoever inherits it can send authenticated mail as you.
Final checklist
- [ ] Sender inventory reviewed by marketing, finance, support
- [ ] Exactly one SPF record, under 10 lookups, ends ~all (then -all)
- [ ] DKIM 2048-bit, verified per selector, rotation scheduled
- [ ] DMARC p=none with rua reporting, 2–4 weeks of data reviewed
- [ ] All legitimate senders aligned (bucket 2 empty)
- [ ] Ramp: quarantine 10% → 50% → 100% → reject, one week+ per step
- [ ] sp=reject set; parked domains locked down
- [ ] Run a full FortifyNet scan to confirm the records grade cleanly
Sources
- RFC 7208 - Sender Policy Framework (SPF)
- RFC 6376 - DomainKeys Identified Mail (DKIM)
- RFC 7489 - Domain-based Message Authentication, Reporting & Conformance (DMARC)
- M3AAWG Email Authentication Best Practices
- Google Workspace - Set up DMARC
- Microsoft 365 - Use DMARC to validate email
- Verizon Data Breach Investigations Report
Originally published at fortifynet.com/blog/guide-email-authentication-rollout. I'm the founder of FortifyNet, a website security scanner; this article comes from our blog, so factor in that founder bias when you read any tool recommendations here.
Top comments (0)