Skip to main content
COSMICBYTEZLABS
NewsSecurityHOWTOsToolsStudyTraining
ProjectsChecklistsAI RankingsNewsletterStatusTagsAbout
Subscribe

Press Enter to search or Esc to close

News
Security
HOWTOs
Tools
Study
Training
Projects
Checklists
AI Rankings
Newsletter
Status
Tags
About
RSS Feed
Reading List
Subscribe

Stay in the Loop

Get the latest security alerts, tutorials, and tech insights delivered to your inbox.

Subscribe NowFree forever. No spam.
COSMICBYTEZLABS

Your trusted source for IT intelligence, cybersecurity insights, and hands-on technical guides.

740+ Articles
120+ Guides

CONTENT

  • Latest News
  • Security Alerts
  • HOWTOs
  • Projects
  • Exam Prep

RESOURCES

  • Search
  • Browse Tags
  • Newsletter Archive
  • Reading List
  • RSS Feed

COMPANY

  • About Us
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CosmicBytez Labs. All rights reserved.

System Status: Operational
  1. Home
  2. HOWTOs
  3. Email Authentication: Deploying SPF, DKIM, and DMARC to Stop Spoofing
Email Authentication: Deploying SPF, DKIM, and DMARC to Stop Spoofing
HOWTOIntermediate

Email Authentication: Deploying SPF, DKIM, and DMARC to Stop Spoofing

Step-by-step guide to implementing SPF, DKIM, and DMARC on your domain — eliminate email spoofing, prevent phishing, and gain full visibility into who sends mail on your behalf.

Dylan H.

Tutorials

April 20, 2026
11 min read

Prerequisites

  • DNS management access for your domain (registrar or hosting panel)
  • Access to your email server or email provider (Exchange Online, Google Workspace, Postfix, etc.)
  • Basic familiarity with DNS record types (TXT, MX, CNAME)
  • A working MX record already configured for your domain

Introduction

Email spoofing remains one of the most effective vectors for phishing attacks, business email compromise (BEC), and brand impersonation. Without authentication controls, anyone on the internet can send an email claiming to be ceo@yourcompany.com — and most mail clients will display it with no visible warning.

The three-layer email authentication stack — SPF, DKIM, and DMARC — closes this gap. Together they let receiving mail servers verify that:

  • Mail from your domain comes from authorized servers (SPF)
  • The message content hasn't been tampered with in transit (DKIM)
  • Unauthenticated mail is quarantined or rejected, and you receive reports about it (DMARC)

This guide walks you through deploying all three, starting with a monitoring-only DMARC policy and progressing to full enforcement — the approach recommended by CISA, Microsoft, and Google.


Prerequisites

  • DNS management console for your domain
  • Admin access to your email platform (Exchange Online, Google Workspace, Postfix with OpenDKIM, etc.)
  • dig or nslookup available locally for validation

Understanding the Protocols

ProtocolWhat It DoesDNS Record Type
SPFLists IP addresses and mail servers authorized to send email for your domainTXT on @ / root
DKIMCryptographically signs outbound mail; receiving servers verify the signature against your public keyTXT on selector._domainkey
DMARCPolicy layer that tells receivers what to do when SPF/DKIM fail, and where to send reportsTXT on _dmarc

DMARC requires at least one of SPF or DKIM to align (the From: domain must match the authenticated domain). This alignment check is what closes the "authenticated but still spoofed" loophole.


Step 1: Configure SPF

SPF is a TXT record on your domain's root (@) that lists all mail-sending services authorized for your domain.

Identify your sending sources

Before writing the record, list every service that sends email as your domain:

  • Primary mail server (on-prem Exchange, Postfix, etc.)
  • Microsoft 365 / Google Workspace
  • Marketing platforms (Mailchimp, HubSpot, SendGrid, Resend, etc.)
  • Ticketing systems, CRMs, monitoring alerts
  • Transactional email providers

Build the SPF record

# Basic SPF structure
v=spf1 <mechanisms> <all>

Common mechanisms:

# Authorize Microsoft 365
v=spf1 include:spf.protection.outlook.com -all
 
# Authorize Google Workspace
v=spf1 include:_spf.google.com -all
 
# Authorize both + a specific mail server IP
v=spf1 include:spf.protection.outlook.com include:_spf.google.com ip4:203.0.113.10 -all
 
# Include a third-party sender (e.g. SendGrid)
v=spf1 include:spf.protection.outlook.com include:sendgrid.net -all

The final qualifier controls what happens to non-matching mail:

QualifierMeaning
-allFail — reject mail not matching (recommended for production)
~allSoftFail — accept but mark (use during testing)
?allNeutral — no policy (avoid in production)
+allPass everything — never use this

Publish the SPF record

In your DNS console, create a TXT record:

Host:  @  (or your bare domain, e.g. example.com)
Type:  TXT
TTL:   3600
Value: v=spf1 include:spf.protection.outlook.com -all

SPF lookup limit: SPF allows a maximum of 10 DNS lookups per evaluation. Each include: costs one lookup. Use ip4: and ip6: mechanisms for static IPs to save lookups. Tools like MXToolbox SPF Surveyor can count your lookups.

Verify SPF

# Check your SPF record
dig TXT example.com | grep spf
 
# Or use nslookup
nslookup -type=TXT example.com
 
# Expected output
example.com. 3600 IN TXT "v=spf1 include:spf.protection.outlook.com -all"

Step 2: Configure DKIM

DKIM uses asymmetric cryptography. Your mail server signs outbound messages with a private key; the public key is published in DNS for receivers to verify.

Option A: Microsoft 365 (Exchange Online)

Microsoft 365 generates DKIM keys per domain. Enable DKIM signing in the Defender portal:

# Connect to Exchange Online PowerShell
Connect-ExchangeOnline -UserPrincipalName admin@example.com
 
# Check current DKIM status
Get-DkimSigningConfig -Identity example.com | Format-List
 
# Enable DKIM signing
Set-DkimSigningConfig -Identity example.com -Enabled $true
 
# If the domain hasn't had DKIM set up before, use:
New-DkimSigningConfig -DomainName example.com -Enabled $true

Microsoft will display two CNAME records to publish in DNS:

selector1._domainkey.example.com → selector1-example-com._domainkey.example.onmicrosoft.com
selector2._domainkey.example.com → selector2-example-com._domainkey.example.onmicrosoft.com

Publish both CNAME records in your DNS console, then re-run Set-DkimSigningConfig to activate.

Option B: Google Workspace

  1. Go to Admin Console → Apps → Google Workspace → Gmail → Authenticate email
  2. Select your domain and click Generate new record
  3. Google provides a TXT record value for google._domainkey.example.com
  4. Publish the TXT record in your DNS console
  5. Return to Admin Console and click Start authentication

Option C: Postfix with OpenDKIM (Linux)

# Install OpenDKIM
sudo apt install opendkim opendkim-tools -y
 
# Generate a 2048-bit key pair
sudo mkdir -p /etc/opendkim/keys/example.com
sudo opendkim-genkey -b 2048 -d example.com -D /etc/opendkim/keys/example.com -s mail -v
 
# Set permissions
sudo chown opendkim:opendkim /etc/opendkim/keys/example.com/mail.private
sudo chmod 600 /etc/opendkim/keys/example.com/mail.private
 
# View the public key record to publish in DNS
cat /etc/opendkim/keys/example.com/mail.txt

The output will be a TXT record for mail._domainkey.example.com. Publish it in DNS.

Configure /etc/opendkim.conf:

Mode                  sv
SubDomains            no
AutoRestart           yes
AutoRestartRate       10/1M
Syslog                yes
SyslogSuccess         yes
LogWhy                yes
Canonicalization      relaxed/simple
Domain                example.com
Selector              mail
KeyFile               /etc/opendkim/keys/example.com/mail.private
Socket                inet:8891@localhost
PidFile               /run/opendkim/opendkim.pid
OversignHeaders       From

Add milter configuration to /etc/postfix/main.cf:

milter_default_action = accept
milter_protocol       = 6
smtpd_milters         = inet:localhost:8891
non_smtpd_milters     = inet:localhost:8891
sudo systemctl enable --now opendkim
sudo systemctl restart postfix

Verify DKIM

# Check DKIM public key is published (replace 'mail' with your selector)
dig TXT mail._domainkey.example.com
 
# For Microsoft 365 selectors
dig TXT selector1._domainkey.example.com
dig TXT selector2._domainkey.example.com
 
# Send a test email to check-auth@verifier.port25.com and review the reply
# It will show DKIM pass/fail in the results

Step 3: Deploy DMARC (Start with Monitoring)

DMARC ties SPF and DKIM together with a policy and a reporting mechanism. Always start with p=none (monitor mode) to collect data before enforcing — rushing to p=reject without analysis will break legitimate mail flows.

Phase 1 — Monitor only (p=none)

Publish this TXT record on _dmarc.example.com:

v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com; ruf=mailto:dmarc-forensics@example.com; fo=1; adkim=r; aspf=r; pct=100
TagValueMeaning
pnoneNo enforcement — monitor only
ruamailto:...Aggregate report destination (daily XML digests)
rufmailto:...Forensic/failure report destination (per-message)
fo1Send forensic reports when SPF or DKIM fails
adkimrRelaxed DKIM alignment
aspfrRelaxed SPF alignment
pct100Apply policy to 100% of messages

Tip: Point rua to a dedicated mailbox or a DMARC reporting SaaS (dmarcian, Postmark, Google Postmaster Tools) — aggregate reports are compressed XML and difficult to parse manually.

Publish in DNS:

Host:  _dmarc
Type:  TXT
TTL:   3600
Value: v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com; fo=1

Phase 2 — Quarantine (p=quarantine)

After 2–4 weeks of aggregate report analysis and confirming all legitimate senders are covered by SPF/DKIM, escalate:

v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@example.com; fo=1; pct=100

Mail failing DMARC alignment goes to the recipient's spam/junk folder. Start with pct=10 to apply to only 10% of messages and ramp up as confidence grows.

Phase 3 — Reject (p=reject)

Full enforcement — unauthenticated mail is rejected at the gateway:

v=DMARC1; p=reject; rua=mailto:dmarc-reports@example.com; fo=1; pct=100

Before moving to p=reject, verify:

  • All expected sending services appear as DMARC pass in aggregate reports
  • No legitimate internal systems are sending unauthenticated mail
  • Subdomains are covered (or explicitly set sp=reject for subdomain policy)

DMARC for subdomains

To apply a separate policy to subdomains:

v=DMARC1; p=reject; sp=quarantine; rua=mailto:dmarc-reports@example.com; fo=1

Step 4: Monitor with DMARC Aggregate Reports

DMARC aggregate reports (RUA) are XML files sent daily by major receivers (Google, Microsoft, Yahoo, etc.). They show:

  • Source IP addresses sending mail as your domain
  • SPF and DKIM pass/fail status per source
  • Volume of messages per source

Parse reports with parsedmarc (Python)

pip install parsedmarc elasticsearch
 
# Parse a local aggregate report XML
parsedmarc report.xml.gz
 
# Parse reports from a mailbox and output to JSON
parsedmarc --imap-host imap.example.com \
           --imap-user dmarc-reports@example.com \
           --imap-password 'yourpassword' \
           -o /var/log/dmarc/

Quick sanity check without tooling

# Decode and inspect a report manually
zcat report.xml.gz | python3 -c "
import sys
from xml.dom.minidom import parseString
print(parseString(sys.stdin.read()).toprettyxml(indent='  '))
" | less

Key fields to review in each report:

<record>
  <row>
    <source_ip>203.0.113.45</source_ip>   <!-- Who sent the mail -->
    <count>142</count>                      <!-- How many messages -->
    <policy_evaluated>
      <disposition>none</disposition>       <!-- What happened -->
      <dkim>pass</dkim>                     <!-- DKIM result -->
      <spf>pass</spf>                       <!-- SPF result -->
    </policy_evaluated>
  </row>
</record>

Any source IP showing dkim>fail and spf>fail is sending unauthenticated mail as your domain and warrants investigation.


Verification and Testing

Full authentication check

Send a test message to check-auth@verifier.port25.com — you'll receive an automated reply showing SPF, DKIM, and DMARC results.

MXToolbox bulk check

# Use the MXToolbox command-line equivalent via curl (for scripting)
# Or visit https://mxtoolbox.com/EmailHeaders.aspx and paste raw headers
 
# Check SPF
dig TXT example.com | grep "v=spf1"
 
# Check DKIM (replace selector and domain)
dig TXT mail._domainkey.example.com | grep "v=DKIM1"
 
# Check DMARC
dig TXT _dmarc.example.com | grep "v=DMARC1"

Inspect email headers manually

In any received email, view the full headers and look for the Authentication-Results header:

Authentication-Results: mx.google.com;
  dkim=pass header.i=@example.com header.s=mail header.b=AbCdEfGh;
  spf=pass (google.com: domain of sender@example.com designates 203.0.113.10 as permitted sender) smtp.mailfrom=sender@example.com;
  dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=example.com

All three should show pass for legitimate outbound mail.

BIMI readiness (bonus)

Once DMARC is at p=quarantine or p=reject, you're eligible for BIMI (Brand Indicators for Message Identification), which displays your logo in supported mail clients. BIMI requires a verified mark certificate (VMC) for full support, but the _bimi TXT record is free to publish for self-asserted logos.


Troubleshooting

SPF PermError: too many DNS lookups

SPF evaluations are capped at 10 DNS lookups. Flatten nested include: chains by replacing them with explicit ip4: and ip6: blocks. Use tools like dmarcian's SPF Surveyor or kitterman.com/spf/validate.html to count your lookups.

# Before (3 includes, each with sub-lookups)
v=spf1 include:sendgrid.net include:mailchimp.com include:spf.protection.outlook.com -all
 
# After (flatten where possible)
v=spf1 ip4:149.72.0.0/16 ip4:198.2.128.0/18 include:spf.protection.outlook.com -all

DKIM signature verification failures

  • Clock skew: DKIM timestamps must be within 5 minutes. Ensure NTP is synchronized on your mail server (timedatectl status).
  • Line length canonicalization: Use relaxed/simple canonicalization (Canonicalization relaxed/simple in OpenDKIM). Some forwarders modify whitespace.
  • Key mismatch: Confirm the selector DNS record matches the private key used for signing. Regenerate if uncertain.
  • Key size: 1024-bit keys are now considered weak. Use 2048-bit minimum.

DMARC alignment failures from mailing lists

Mailing list software often rewrites the From: header or adds footers that break DKIM signatures. Solutions:

  • Move to relaxed alignment (adkim=r) if not already set
  • Work with mailing list operators to implement ARC (Authenticated Received Chain)
  • Add the mailing list IP to SPF so SPF alignment can carry DMARC even when DKIM fails

Legitimate mail going to spam after p=quarantine

Review your DMARC aggregate reports to find the failing source IP. Common causes:

  • An internal application server not listed in SPF
  • A third-party service using your domain without DKIM signing enabled
  • A subdomain without its own SPF/DKIM records inheriting the parent policy

Fix: add the missing source to SPF, enable DKIM signing for the service, or set a permissive sp= subdomain policy temporarily.

DMARC reports not arriving

  • Confirm your rua= email address is correct and the mailbox exists
  • If the report destination is on a different domain, publish a DMARC TXT record authorizing the cross-domain reporting:
# On the domain receiving reports (reports.example.net)
# if the sending domain is example.com:
example.com._report._dmarc.reports.example.net. TXT "v=DMARC1;"

Summary

You've deployed a complete email authentication stack:

StepRecordStatus
1SPF TXT on @Authorizes legitimate senders
2DKIM TXT/CNAME on selector._domainkeySigns and verifies message integrity
3DMARC TXT on _dmarcEnforces policy and collects reports

Recommended progression timeline:

  1. Week 1–2: Deploy SPF and DKIM, publish DMARC at p=none
  2. Week 3–6: Analyze aggregate reports, remediate all unknown senders
  3. Week 7–8: Escalate to p=quarantine; pct=25, monitor for breakage
  4. Week 9–10: Increase to pct=100 at quarantine
  5. Week 11+: Move to p=reject for full enforcement

Email authentication is not a one-time task — revisit your SPF record whenever you onboard a new SaaS tool that sends mail as your domain, and rotate DKIM keys annually. Set a recurring calendar reminder.

For compliance programs, DMARC at p=reject satisfies email authentication requirements in NIST SP 800-177, CIS Control 9, and is mandated by CISA BOD 18-01 for US federal agencies.

#email-security#spf#dkim#dmarc#dns#anti-phishing#anti-spoofing#compliance

Related Articles

Network Traffic Analysis with Zeek: From Deployment to Threat Detection

Deploy Zeek (formerly Bro) on Linux to passively monitor network traffic, generate structured logs, write detection scripts, and forward data to your SIEM...

6 min read

Suricata IDS/IPS Deployment: From Install to Active Threat Detection

Deploy Suricata as a full-featured Network Intrusion Detection and Prevention System on Ubuntu. Covers installation, interface capture, Emerging Threats...

10 min read

Container Security Scanning with Trivy: Images, IaC, and CI/CD

Learn how to use Trivy to scan container images, Dockerfiles, Kubernetes manifests, and Terraform for vulnerabilities and misconfigurations — then...

7 min read
Back to all HOWTOs