SPF and DMARC Configuration: Complete Email Authentication Guide
Introduction
Email authentication has become essential for modern mail servers. While DKIM provides cryptographic signing, two other critical protocols complete the authentication trinity: SPF (Sender Policy Framework) and DMARC (Domain-based Message Authentication, Reporting, and Conformance).
SPF allows domain owners to specify which mail servers are authorized to send email on behalf of their domain. When a receiving server gets an email claiming to be from your domain, it checks your SPF record to verify the sending server is authorized. This simple but powerful mechanism prevents spammers from spoofing your domain.
DMARC builds on both SPF and DKIM by adding policy enforcement and reporting capabilities. It tells receiving mail servers what to do when SPF or DKIM checks fail, and provides detailed reports about who is sending email using your domain. This visibility is crucial for identifying legitimate mail flow and detecting abuse.
Together, SPF, DKIM, and DMARC provide comprehensive email authentication that:
- Dramatically improves email deliverability
- Protects your domain from spoofing and phishing
- Provides visibility into your email ecosystem
- Meets requirements of major email providers
- Builds and maintains sender reputation
This comprehensive guide walks you through configuring SPF and DMARC for your domain, implementing best practices, monitoring authentication results, and troubleshooting common issues.
Prerequisites
Before configuring SPF and DMARC, ensure you have:
Domain Requirements
- A registered domain name (e.g., example.com)
- Access to your domain's DNS management panel
- Understanding of your current email infrastructure
- Knowledge of all legitimate mail sources for your domain
Email Server Requirements
- Working mail server sending email
- DKIM configured and operational (strongly recommended)
- List of all IPs and services that send email for your domain
- Access to mail server logs
Knowledge Prerequisites
- DNS record management experience
- Basic understanding of email headers
- Familiarity with SPF, DKIM, DMARC concepts
- Ability to read and interpret authentication results
Understanding SPF
What is SPF?
Sender Policy Framework (SPF) is an email validation system that detects and prevents email spoofing. It works by allowing domain owners to publish a list of authorized mail servers in DNS.
How SPF Works
- Publication: You publish an SPF record in your DNS as a TXT record
- Email Sent: Someone sends email claiming to be from your domain
- SPF Check: Receiving server queries DNS for your SPF record
- IP Comparison: Receiving server compares sender's IP against authorized IPs
- Result: SPF passes, fails, or returns neutral/softfail
- Action: Receiving server acts based on SPF result
SPF Results
- Pass: Sender IP is authorized
- Fail: Sender IP is not authorized (hard fail)
- SoftFail (~all): IP not authorized but don't reject
- Neutral: No policy statement
- None: No SPF record found
- TempError: Temporary DNS problem
- PermError: SPF record has errors
Understanding DMARC
What is DMARC?
DMARC (Domain-based Message Authentication, Reporting, and Conformance) is an email authentication protocol that uses SPF and DKIM results to determine message authenticity and provides policy enforcement and reporting.
How DMARC Works
- Policy Publication: You publish a DMARC policy in DNS
- Authentication Check: Receiving server checks SPF and DKIM
- Alignment Check: Verifies domain alignment
- Policy Application: Applies your policy (none/quarantine/reject)
- Reporting: Sends aggregate and forensic reports to you
DMARC Policies
- none: Monitor only, don't reject (recommended for initial deployment)
- quarantine: Move failing messages to spam/junk folder
- reject: Reject failing messages entirely
DMARC Alignment
DMARC requires either SPF or DKIM to pass AND align:
- SPF Alignment: Return-Path domain matches From domain
- DKIM Alignment: DKIM signature domain matches From domain
- Relaxed Alignment: Subdomains allowed (default)
- Strict Alignment: Exact domain match required
Step 1: Analyze Your Email Infrastructure
Before creating SPF records, identify all legitimate email sources:
Identify Mail Servers
# Check your mail server's IP
dig mail.example.com A +short
# Check MX records
dig example.com MX +short
# Check reverse DNS
dig -x YOUR_IP +short
Common Email Sources to Consider
- Your mail server: Primary SMTP server
- Backup MX servers: Secondary mail servers
- Web servers: Applications sending email
- Third-party services:
- Mailchimp, SendGrid, Amazon SES
- Google Workspace, Microsoft 365
- CRM systems, monitoring tools
- Help desk software
- Other infrastructure: Any server running mail-enabled applications
Document Email Sources
Create a list:
Primary mail server: 203.0.113.10 (mail.example.com)
Web server: 203.0.113.20 (www.example.com)
SendGrid: include:sendgrid.net
Google Workspace: include:_spf.google.com
Step 2: Create SPF Record
Basic SPF Syntax
SPF records are published as DNS TXT records with this format:
v=spf1 [mechanisms] [qualifier]all
SPF Mechanisms
- ip4: Authorize IPv4 address or range
- ip6: Authorize IPv6 address or range
- a: Authorize A record of domain
- mx: Authorize MX records of domain
- include: Include another domain's SPF record
- exists: Advanced DNS-based authorization
- all: Catch-all for everything else
SPF Qualifiers
- + (Pass): Authorized (default if not specified)
- - (Fail): Not authorized, hard fail
- ~ (SoftFail): Not authorized but don't reject
- ? (Neutral): No policy assertion
Common SPF Examples
Simple mail server:
v=spf1 mx a ip4:203.0.113.10 ~all
With third-party services:
v=spf1 mx a ip4:203.0.113.10 include:_spf.google.com include:sendgrid.net ~all
Multiple IPs:
v=spf1 ip4:203.0.113.10 ip4:203.0.113.20 ip4:203.0.113.30 ~all
IP range:
v=spf1 ip4:203.0.113.0/24 ~all
Strict (reject unauthorized):
v=spf1 mx a ip4:203.0.113.10 -all
SPF Best Practices
- Start with ~all: Use soft fail initially, move to -all after testing
- Be specific: Only include necessary mechanisms
- Avoid too many includes: Maximum 10 DNS lookups allowed
- Use IP ranges carefully: Only include IPs you control
- Keep it simple: Complex SPF records are harder to maintain
Example SPF for Common Scenarios
Scenario 1: Self-hosted mail server only
v=spf1 mx a ip4:203.0.113.10 ~all
Scenario 2: Mail server + Google Workspace
v=spf1 ip4:203.0.113.10 include:_spf.google.com ~all
Scenario 3: Multiple services
v=spf1 ip4:203.0.113.10 include:_spf.google.com include:servers.mcsv.net include:sendgrid.net ~all
Scenario 4: No mail server (third-party only)
v=spf1 include:_spf.google.com -all
Scenario 5: Mail server + backup MX + SendGrid
v=spf1 mx a ip4:203.0.113.10 ip4:203.0.113.11 include:sendgrid.net ~all
Step 3: Publish SPF Record
Add DNS TXT Record
In your DNS management panel, create a TXT record:
Name/Host: @ (or leave blank for root domain) Type: TXT Value: Your SPF record
Example:
Name: @
Type: TXT
Value: v=spf1 mx a ip4:203.0.113.10 include:_spf.google.com ~all
TTL: 3600
Important Notes
- Each domain needs its own SPF record
- Only ONE SPF record per domain (multiple TXT records are OK, but only one can be SPF)
- Subdomains can have separate SPF records
- If subdomain has no SPF record, parent domain's record is not used
Verify SPF Publication
# Check SPF record
dig example.com TXT +short | grep spf
# Alternative
host -t TXT example.com | grep spf
# Query specific nameserver
dig @8.8.8.8 example.com TXT +short | grep spf
Expected output:
"v=spf1 mx a ip4:203.0.113.10 ~all"
Step 4: Test SPF Configuration
Online Testing Tools
MXToolbox SPF Check:
https://mxtoolbox.com/spf.aspx
SPF Query Tool:
https://www.kitterman.com/spf/validate.html
DMARC Analyzer SPF Checker:
https://www.dmarcanalyzer.com/spf/checker/
Command Line Testing
# Basic SPF test
dig example.com TXT +short
# Check if SPF is valid
host -t TXT example.com
Test Email Authentication
Send a test email and check headers:
echo "SPF test email" | mail -s "SPF Test" [email protected]
In Gmail:
- Open the email
- Click "Show original"
- Look for SPF results:
Received-SPF: pass (google.com: domain of [email protected] designates 203.0.113.10 as permitted sender)
Or in Authentication-Results:
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of [email protected] designates 203.0.113.10 as permitted sender)
Common SPF Test Results
Pass:
Received-SPF: pass
Your IP is authorized, SPF is working correctly.
SoftFail:
Received-SPF: softfail
Your IP not explicitly authorized, check SPF record.
Fail:
Received-SPF: fail
Your IP is not authorized, email may be rejected.
None:
Received-SPF: none
No SPF record found for your domain.
Step 5: Create DMARC Record
Basic DMARC Syntax
DMARC records are published as DNS TXT records at _dmarc.yourdomain.com:
v=DMARC1; p=policy; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1
DMARC Tags
Required:
- v=DMARC1: Version identifier
- p=: Policy for domain (none/quarantine/reject)
Recommended:
- rua=: Aggregate report email address
- ruf=: Forensic report email address
- pct=: Percentage of emails to apply policy (default 100)
- sp=: Policy for subdomains (default: same as p)
Optional:
- adkim=: DKIM alignment mode (r=relaxed, s=strict)
- aspf=: SPF alignment mode (r=relaxed, s=strict)
- fo=: Forensic reporting options
- rf=: Forensic report format
- ri=: Aggregate report interval (seconds)
DMARC Policies Explained
p=none (Monitoring mode):
- No action taken on failures
- Reports sent for analysis
- Recommended for initial deployment
- Learn about your email ecosystem
p=quarantine (Quarantine mode):
- Failing emails moved to spam/junk
- Partial enforcement
- Next step after monitoring
- Still allows email delivery
p=reject (Reject mode):
- Failing emails rejected at SMTP level
- Full enforcement
- Maximum protection
- Risk of legitimate mail loss if misconfigured
DMARC Example Records
Level 1: Monitoring (Start here)
v=DMARC1; p=none; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1; pct=100
Level 2: Partial Enforcement
v=DMARC1; p=quarantine; pct=10; rua=mailto:[email protected]; sp=none
Level 3: Quarantine
v=DMARC1; p=quarantine; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1
Level 4: Full Protection
v=DMARC1; p=reject; rua=mailto:[email protected]; sp=reject; aspf=s; adkim=s; fo=1
With subdomain policy:
v=DMARC1; p=reject; sp=quarantine; rua=mailto:[email protected]
DMARC Tag Details
pct (Percentage):
pct=25 # Apply policy to 25% of email
pct=50 # Apply policy to 50% of email
pct=100 # Apply policy to all email (default)
fo (Forensic Options):
fo=0 # Report if all mechanisms fail (default)
fo=1 # Report if any mechanism fails
fo=d # Report if DKIM fails
fo=s # Report if SPF fails
ri (Report Interval):
ri=86400 # Daily reports (default)
ri=3600 # Hourly reports
Step 6: Publish DMARC Record
Add DNS TXT Record
In your DNS management panel:
Name/Host: _dmarc
or
Name/Host: _dmarc.example.com.
Type: TXT Value: Your DMARC record
Example:
Name: _dmarc
Type: TXT
Value: v=DMARC1; p=none; rua=mailto:[email protected]; fo=1
TTL: 3600
Set Up Report Email Address
Create an email address to receive DMARC reports:
# Add to virtual mailboxes (Postfix)
echo "[email protected] example.com/dmarc-reports/" | sudo tee -a /etc/postfix/virtual_mailboxes
# Add to Dovecot users
NEW_PASSWORD=$(doveadm pw -s SHA512-CRYPT -p 'ReportPassword')
echo "[email protected]:$NEW_PASSWORD" | sudo tee -a /etc/dovecot/users
# Rebuild maps
sudo postmap /etc/postfix/virtual_mailboxes
sudo systemctl reload postfix dovecot
Or use a third-party DMARC reporting service:
- DMARC Analyzer: https://www.dmarcanalyzer.com/
- Postmark: https://dmarc.postmarkapp.com/
- dmarcian: https://dmarcian.com/
Verify DMARC Publication
# Check DMARC record
dig _dmarc.example.com TXT +short
# Alternative
host -t TXT _dmarc.example.com
# Query Google's DNS
dig @8.8.8.8 _dmarc.example.com TXT +short
Expected output:
"v=DMARC1; p=none; rua=mailto:[email protected]; fo=1"
Step 7: Test DMARC Configuration
Online Testing Tools
MXToolbox DMARC Check:
https://mxtoolbox.com/dmarc.aspx
DMARC Analyzer:
https://www.dmarcanalyzer.com/dmarc/dmarc-check/
EasyDMARC:
https://easydmarc.com/tools/dmarc-lookup
Send Test Email
echo "DMARC test email" | mail -s "DMARC Test" [email protected]
Check email headers for DMARC results:
Authentication-Results: mx.google.com;
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=example.com
Result meanings:
- dmarc=pass: SPF or DKIM passed with alignment
- dmarc=fail: Neither SPF nor DKIM passed with alignment
- p=NONE: Your policy is monitoring only
- p=QUARANTINE: Your policy requests quarantine
- p=REJECT: Your policy requests rejection
Step 8: Configure for Subdomains
Option 1: Explicit Subdomain Records
Create separate SPF and DMARC for each subdomain:
# SPF for subdomain
subdomain.example.com. TXT "v=spf1 ip4:203.0.113.10 ~all"
# DMARC for subdomain
_dmarc.subdomain.example.com. TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]"
Option 2: Use Subdomain Policy
In main DMARC record:
v=DMARC1; p=reject; sp=quarantine; rua=mailto:[email protected]
- p=reject: Policy for main domain
- sp=quarantine: Policy for subdomains
Option 3: Block Unused Subdomains
If you don't send email from subdomains:
# SPF for subdomains
*.example.com. TXT "v=spf1 -all"
# DMARC for subdomains
_dmarc.*.example.com. TXT "v=DMARC1; p=reject"
This prevents attackers from sending email as [email protected].
Step 9: Monitor DMARC Reports
Aggregate Reports (RUA)
Sent daily by most email providers, contains:
- Number of messages received
- SPF results
- DKIM results
- DMARC pass/fail statistics
- Source IPs
Format: XML file attached to email
Forensic Reports (RUF)
Sent when authentication fails, contains:
- Full headers of failed message
- SPF/DKIM/DMARC failure reasons
- More detailed than aggregate reports
Format: RFC 5322 format (email message)
Reading DMARC Reports
Reports are XML, which is hard to read. Options:
1. Online parsers:
2. DMARC reporting services:
- DMARC Analyzer
- Postmark DMARC
- dmarcian
3. Self-hosted:
- Parsedmarc: https://github.com/domainaware/parsedmarc
- DMARC Visualizer: https://github.com/techsneeze/dmarcts-report-viewer
Sample Report Analysis
<record>
<row>
<source_ip>203.0.113.10</source_ip>
<count>100</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>pass</dkim>
<spf>pass</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>example.com</header_from>
</identifiers>
<auth_results>
<dkim>
<domain>example.com</domain>
<result>pass</result>
</dkim>
<spf>
<domain>example.com</domain>
<result>pass</result>
</spf>
</auth_results>
</record>
This shows:
- 100 emails from IP 203.0.113.10
- Both SPF and DKIM passed
- DMARC passed
- No action taken (policy=none)
Step 10: Progressive DMARC Deployment
Don't jump straight to p=reject. Follow this timeline:
Phase 1: Monitoring (Week 1-4)
v=DMARC1; p=none; rua=mailto:[email protected]; fo=1
Actions:
- Collect reports for 2-4 weeks
- Identify all legitimate mail sources
- Fix any SPF/DKIM issues
- Document email ecosystem
Phase 2: Partial Quarantine (Week 5-8)
v=DMARC1; p=quarantine; pct=10; rua=mailto:[email protected]
Actions:
- Apply quarantine to 10% of mail
- Monitor for false positives
- Gradually increase pct (10% → 25% → 50% → 100%)
- Fix any discovered issues
Phase 3: Full Quarantine (Week 9-12)
v=DMARC1; p=quarantine; pct=100; rua=mailto:[email protected]
Actions:
- Monitor for legitimate mail in quarantine
- Ensure all sources properly authenticated
- Collect data on remaining failures
Phase 4: Reject (Week 13+)
v=DMARC1; p=reject; rua=mailto:[email protected]; sp=reject
Actions:
- Full protection enabled
- Continue monitoring reports
- Maintain SPF/DKIM configuration
- Regular audits
Troubleshooting Common Issues
Issue 1: SPF Hard Fail
Symptoms: Legitimate email failing SPF
Check:
# Verify SPF record
dig example.com TXT +short | grep spf
# Test from your server
echo "Test" | mail -s "SPF Test" -r [email protected] [email protected]
# Check headers in received email
Solutions:
- Add missing IPs to SPF record
- Include third-party service SPF
- Change -all to ~all for testing
- Verify IP in SPF matches sending server
Issue 2: Too Many DNS Lookups
Symptoms: SPF returns PermError
Cause: SPF limit is 10 DNS lookups
Check:
# Count includes in your SPF
dig example.com TXT +short | grep -o "include:" | wc -l
Solutions:
- Replace includes with ip4/ip6 where possible
- Consolidate multiple includes
- Use IP ranges instead of individual IPs
- Remove unnecessary includes
Example fix:
# Before (11 lookups - too many)
v=spf1 include:_spf.google.com include:sendgrid.net include:servers.mcsv.net include:spf.protection.outlook.com mx a ~all
# After (fewer lookups)
v=spf1 include:_spf.google.com include:sendgrid.net ip4:203.0.113.10 ~all
Issue 3: DMARC Alignment Failure
Symptoms: SPF/DKIM pass but DMARC fails
Cause: Domain mismatch between From header and SPF/DKIM domains
Check email headers:
From: [email protected]
Return-Path: <[email protected]>
DKIM-Signature: d=mail.example.com
Solutions:
For SPF alignment: Ensure Return-Path domain matches From domain:
# In Postfix main.cf
smtp_helo_name = example.com
For DKIM alignment: Ensure DKIM signature domain matches From domain:
# In OpenDKIM signing.table
*@example.com default._domainkey.example.com
Use relaxed alignment:
v=DMARC1; p=none; aspf=r; adkim=r; rua=mailto:[email protected]
Issue 4: No DMARC Reports Received
Symptoms: Not receiving any reports
Check:
# Verify DMARC record
dig _dmarc.example.com TXT +short
# Test email address works
echo "Test" | mail -s "Test" [email protected]
Reasons:
- Email address doesn't exist or unreachable
- Not enough email volume (reports sent daily if volume exists)
- DNS record incorrect
- Receiving provider doesn't send reports (not all do)
Solutions:
- Verify email address receives mail
- Wait 24-48 hours for first reports
- Send more test emails to major providers
- Use third-party reporting service
Issue 5: Legitimate Mail Quarantined/Rejected
Symptoms: Valid email not delivered with p=quarantine or p=reject
Diagnosis:
- Check DMARC reports for failing sources
- Verify SPF record includes all sources
- Confirm DKIM signing all mail
- Check domain alignment
Solutions:
- Add missing IPs to SPF
- Configure DKIM for all mail sources
- Fix Return-Path domain
- Temporarily reduce policy: p=none or p=quarantine with pct=10
Best Practices
1. Start Conservative
- Begin with p=none
- Use ~all for SPF initially
- Monitor reports thoroughly
- Gradually increase enforcement
2. Maintain Complete Records
Document all email sources:
Mail server: 203.0.113.10 (mail.example.com)
Web server: 203.0.113.20 (www.example.com)
SendGrid: include:sendgrid.net
Monitoring: 203.0.113.30 (monitor.example.com)
3. Regular Audits
Monthly tasks:
# Check SPF
dig example.com TXT +short | grep spf
# Check DMARC
dig _dmarc.example.com TXT +short
# Review reports
# Check for new sources or failures
4. Protect Subdomains
Even unused subdomains:
*.example.com. TXT "v=spf1 -all"
_dmarc.*.example.com. TXT "v=DMARC1; p=reject"
5. Monitor Continuously
- Review DMARC reports weekly
- Set up alerts for authentication failures
- Track pass/fail rates over time
- Investigate any sudden changes
6. Coordinate with Teams
- Inform marketing team before enforcement
- Document all third-party email services
- Test before deploying new services
- Maintain update procedures
Advanced Configuration
Multiple Report Addresses
rua=mailto:[email protected],mailto:[email protected],mailto:[email protected]
External Report Addresses
To send reports to external domains, the external domain must authorize it:
At example.com:
v=DMARC1; p=none; rua=mailto:[email protected]
At external.com:
example.com._report._dmarc.external.com. TXT "v=DMARC1"
Percentage-Based Policy
v=DMARC1; p=reject; pct=25; rua=mailto:[email protected]
Applies reject policy to 25% of failing mail, allowing gradual rollout.
Strict Alignment
v=DMARC1; p=reject; aspf=s; adkim=s; rua=mailto:[email protected]
Requires exact domain match (not subdomains) for SPF and DKIM.
Monitoring Script
Create automated monitoring:
sudo nano /usr/local/bin/check-spf-dmarc.sh
Add:
#!/bin/bash
DOMAIN="example.com"
echo "=== SPF and DMARC Check ==="
echo ""
echo "SPF Record:"
dig $DOMAIN TXT +short | grep spf
echo ""
echo "DMARC Record:"
dig _dmarc.$DOMAIN TXT +short
echo ""
echo "SPF Test:"
host -t TXT $DOMAIN | grep spf
echo ""
echo "DMARC Reports (last 7 days):"
find ~/Maildir/cur -type f -name "*" -mtime -7 | xargs grep -l "dmarc-reports" | wc -l
Make executable:
sudo chmod +x /usr/local/bin/check-spf-dmarc.sh
Conclusion
You now have complete SPF and DMARC configuration, providing comprehensive email authentication alongside DKIM. Your domain is protected from spoofing, and your email deliverability is significantly improved.
Key Accomplishments
- SPF Configured: Authorized mail servers published in DNS
- DMARC Implemented: Policy and reporting active
- Progressive Deployment: Safe rollout strategy in place
- Monitoring Active: Reports being received and analyzed
- Best Practices: Following industry standards
Complete Authentication Stack
With SPF, DKIM, and DMARC all configured:
- SPF: Validates sending server IP
- DKIM: Cryptographically signs messages
- DMARC: Enforces policy and provides reporting
Next Steps
- Monitor reports weekly: Review DMARC aggregate reports
- Progress to stricter policy: Move from none → quarantine → reject
- Configure subdomains: Protect all subdomains
- Set up automated alerts: Be notified of issues
- Regular audits: Quarterly review of configuration
- Team education: Train staff on email authentication
Important Reminders
- Never skip monitoring phase: Always start with p=none
- Review reports before changing policy: Understand your email ecosystem
- Document all sources: Keep inventory of legitimate senders
- Test thoroughly: Verify each policy change
- Communicate changes: Inform relevant teams
With SPF, DKIM, and DMARC properly configured, you have industry-leading email authentication that protects your domain, improves deliverability, and provides visibility into your email infrastructure. Continue monitoring and maintaining these systems to ensure ongoing protection and optimal email performance.


