DMARC (Domain-based Message Authentication, Reporting & Conformance)¶
Understanding DMARC and how it enforces email authentication policies.
What is DMARC?¶
DMARC (Domain-based Message Authentication, Reporting & Conformance) is an email authentication protocol that builds on SPF and DKIM to:
- Enforce authentication policies - Tell receivers what to do with emails that fail SPF/DKIM
- Prevent domain spoofing - Stop attackers from using your domain
- Provide visibility - Receive reports on who's sending email using your domain
- Improve deliverability - Build trust with email providers
DMARC is the final piece that ties SPF and DKIM together into a complete email authentication framework.
The Problem DMARC Solves¶
SPF and DKIM alone have limitations:
- SPF only checks the envelope sender (MAIL FROM), not the visible From address
- DKIM passes even if the signing domain differs from the From address
- No enforcement - Even with SPF/DKIM, receivers decide what to do with failures
DMARC fixes this by requiring alignment with the From address and providing explicit policy enforcement.
How DMARC Works¶
sequenceDiagram
participant Sender as Mail Server
participant DNS as DNS Server
participant Receiver as Receiving Server
Sender->>Receiver: Email from user@example.com
Receiver->>Receiver: 1. Check SPF
Note over Receiver: SPF Pass ✓
Receiver->>Receiver: 2. Check DKIM
Note over Receiver: DKIM Pass ✓
Receiver->>DNS: 3. Query DMARC policy<br/>_dmarc.example.com
DNS->>Receiver: v=DMARC1; p=reject;<br/>rua=mailto:dmarc@example.com
Receiver->>Receiver: 4. Check Alignment<br/>SPF/DKIM domain vs From domain
alt SPF or DKIM aligned
Receiver->>Receiver: DMARC Pass - Deliver
else Neither aligned + p=reject
Receiver->>Receiver: DMARC Fail - Reject
else Neither aligned + p=quarantine
Receiver->>Receiver: DMARC Fail - Spam folder
else Neither aligned + p=none
Receiver->>Receiver: DMARC Fail - Deliver + Report
end
Receiver->>Sender: 5. Send aggregate report
Note over Receiver,Sender: Daily/weekly reports
The DMARC Process¶
- Authentication - Email is checked with SPF and DKIM
- Alignment Check - SPF/DKIM domains must align with From header
- Policy Lookup - Receiver fetches DMARC policy from DNS
- Policy Application - Receiver takes action based on policy (none/quarantine/reject)
- Reporting - Receiver sends aggregate and forensic reports
DMARC Record Anatomy¶
Basic Structure¶
All DMARC Tags¶
| Tag | Required | Description | Values | Example |
|---|---|---|---|---|
v= |
✅ Yes | Protocol version | DMARC1 |
v=DMARC1 |
p= |
✅ Yes | Policy for domain | none, quarantine, reject |
p=reject |
sp= |
❌ No | Subdomain policy | none, quarantine, reject |
sp=quarantine |
rua= |
❌ No | Aggregate report URI | mailto: addresses |
rua=mailto:dmarc@example.com |
ruf= |
❌ No | Forensic report URI | mailto: addresses |
ruf=mailto:forensic@example.com |
pct= |
❌ No | Percentage of messages | 0-100 |
pct=100 |
adkim= |
❌ No | DKIM alignment mode | r (relaxed), s (strict) |
adkim=r |
aspf= |
❌ No | SPF alignment mode | r (relaxed), s (strict) |
aspf=r |
rf= |
❌ No | Report format | afrf, iodef |
rf=afrf |
ri= |
❌ No | Report interval (seconds) | 0-2147483647 |
ri=86400 |
fo= |
❌ No | Forensic options | 0, 1, d, s |
fo=1 |
DMARC Policies¶
The p= tag defines what receiving servers should do with emails that fail DMARC.
Policy Options¶
p=none (Monitoring Mode)¶
Action: Do nothing, just report
When to use: - Starting DMARC - Monitor first before enforcing - Testing changes - Verify configuration works - Gathering data - Understand your email sources
Pros: - ✅ No risk of blocking legitimate email - ✅ Collect data on authentication failures - ✅ Identify unauthorized senders
Cons: - ❌ Provides no protection (emails still delivered) - ❌ Attackers can still spoof your domain
p=quarantine (Spam Folder)¶
Action: Mark as spam/suspicious
When to use: - After monitoring with p=none for 1-2 weeks - Gradual enforcement - Less aggressive than reject - High confidence in legitimate sources
Pros: - ✅ Protects users while allowing review - ✅ Failed emails accessible if needed - ✅ Lower risk than reject
Cons: - ❌ Some spoofed emails still reach users - ❌ Less protection than reject
p=reject (Maximum Protection)¶
Action: Reject email completely
When to use: - After successful quarantine period - 100% confidence in configuration - Maximum security required
Pros: - ✅ Best protection against spoofing - ✅ Builds strong sender reputation - ✅ Industry best practice
Cons: - ❌ Risk of blocking legitimate email if misconfigured - ❌ No way to recover rejected emails
DMARC Alignment¶
Alignment is the key concept in DMARC - it links SPF/DKIM to the visible From address.
What is Alignment?¶
For DMARC to pass, at least ONE of the following must be true:
- SPF passes AND SPF domain aligns with From header
- DKIM passes AND DKIM domain aligns with From header
Relaxed Alignment (Default)¶
Organizational domains must match:
From: user@example.com
SPF MAIL FROM: bounce@mail.example.com
✓ Aligned (example.com matches)
From: user@example.com
DKIM d=: mail.example.com
✓ Aligned (example.com matches)
Configuration:
Strict Alignment¶
Exact domains must match:
From: user@example.com
SPF MAIL FROM: bounce@mail.example.com
✗ NOT aligned (mail.example.com ≠ example.com)
From: user@example.com
DKIM d=: example.com
✓ Aligned (exact match)
Configuration:
Alignment Examples¶
Example 1: SPF Aligned, DKIM Not Aligned¶
From: user@example.com
MAIL FROM: bounce@example.com (SPF Pass + Aligned ✓)
DKIM d=: mailserver.com (DKIM Pass but NOT Aligned ✗)
Result: DMARC PASS (SPF alignment sufficient)
Example 2: DKIM Aligned, SPF Not Aligned¶
From: user@example.com
MAIL FROM: list@mailinglist.com (SPF Pass but NOT Aligned ✗)
DKIM d=: example.com (DKIM Pass + Aligned ✓)
Result: DMARC PASS (DKIM alignment sufficient)
Example 3: Neither Aligned¶
From: user@example.com
MAIL FROM: attacker@evil.com (SPF Pass but NOT Aligned ✗)
DKIM d=: evil.com (DKIM Pass but NOT Aligned ✗)
Result: DMARC FAIL (no alignment)
Action: Apply policy (none/quarantine/reject)
DMARC Reports¶
DMARC provides two types of reports for visibility into email authentication.
Aggregate Reports (RUA)¶
Daily/weekly XML reports summarizing authentication results.
What's included: - Source IP addresses sending email - SPF/DKIM/DMARC pass/fail counts - Message volume by sender - Policy applied
Example aggregate report structure:
<feedback>
<report_metadata>
<org_name>google.com</org_name>
<date_range>
<begin>1634169600</begin>
<end>1634256000</end>
</date_range>
</report_metadata>
<record>
<row>
<source_ip>192.0.2.1</source_ip>
<count>125</count>
</row>
<identifiers>
<header_from>example.com</header_from>
</identifiers>
<auth_results>
<spf>
<result>pass</result>
</spf>
<dkim>
<result>pass</result>
</dkim>
</auth_results>
</record>
</feedback>
Forensic Reports (RUF)¶
Real-time failure reports with email samples (rarely supported).
What's included: - Full headers of failed message - Authentication failure details - Copy of message (redacted)
Privacy concerns: - May contain sensitive data - Few providers send forensic reports - Most organizations only use aggregate reports
Multiple Report Addresses¶
Comma-separated for multiple recipients.
External Report Destinations¶
To send reports to a different domain, add verification:
# Your domain
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:reports@vendor.com"
# Vendor must publish:
example.com._report._dmarc.vendor.com. IN TXT "v=DMARC1"
DMARC Percentage (pct=)¶
Gradually roll out policy by applying it to only a percentage of messages.
pct=25- Apply policy to 25% of failing messages- Remaining 75% treated as
p=none(deliver + report)
Use Cases¶
Testing policy safely:
Week 1: p=quarantine; pct=10
Week 2: p=quarantine; pct=25
Week 3: p=quarantine; pct=50
Week 4: p=quarantine; pct=100
Gradual reject rollout:
Best practice: Once confident, set pct=100 for full protection.
Subdomain Policy (sp=)¶
Control policy for subdomains separately from the main domain.
p=reject- Policy for example.comsp=quarantine- Policy for *.example.com
When to Use Different Subdomain Policy¶
Example scenario:
- Main domain (
example.com) usesp=reject - Subdomains (
*.example.com) usesp=none(monitoring)
Use cases: - Testing subdomains before enforcing - Different security requirements - Third-party services using subdomains
Subdomain-Specific DMARC¶
Subdomains can have their own DMARC records:
# Main domain
_dmarc.example.com. IN TXT "v=DMARC1; p=reject"
# Subdomain override
_dmarc.mail.example.com. IN TXT "v=DMARC1; p=none"
Subdomain record takes precedence.
Forensic Report Options (fo=)¶
Control when forensic reports are generated.
| Value | Description |
|---|---|
fo=0 |
Generate if both SPF and DKIM fail (default) |
fo=1 |
Generate if either SPF or DKIM fails |
fo=d |
Generate if DKIM fails (regardless of SPF) |
fo=s |
Generate if SPF fails (regardless of DKIM) |
Example:
Note: Few email providers send forensic reports due to privacy concerns.
Setting Up DMARC¶
Step 1: Ensure SPF and DKIM are Working¶
Check with ReputeAPI:
Verify: - ✅ SPF record exists and passes - ✅ DKIM keys configured and signing - ✅ No critical issues
Step 2: Start with p=none¶
Why start with none: - Collect data without risk - Identify all legitimate senders - Catch misconfigurations
Step 3: Set Up Report Monitoring¶
Create mailbox for reports:
Or use DMARC report analyzer: - Postmark DMARC - DMARC Analyzer - EasyDMARC - Valimail
Step 4: Monitor for 1-2 Weeks¶
Review aggregate reports: - Identify all sending sources - Verify 100% pass rate for legitimate mail - Investigate failures
Look for: - ✅ All legitimate senders passing - ❌ Unexpected sources (third-party services, marketing tools) - ❌ Authentication failures
Step 5: Move to p=quarantine¶
Optional: Gradual rollout:
Step 6: Monitor Quarantine¶
Check for issues: - Users reporting missing emails? - Spam folders catching legitimate mail? - Report any new failures?
Duration: 2-4 weeks minimum
Step 7: Move to p=reject¶
Optional: Gradual rollout:
Step 8: Ongoing Monitoring¶
Regular tasks: - Weekly: Review aggregate reports - Monthly: Audit sender sources - Quarterly: Check authentication rates - Always: Investigate new failures
Common DMARC Configurations¶
Configuration 1: Just Starting (Monitoring)¶
Configuration 2: Intermediate (Quarantine)¶
Configuration 3: Maximum Protection (Reject)¶
Configuration 4: Strict Alignment¶
Configuration 5: With Forensic Reports¶
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com; ruf=mailto:forensic@example.com; fo=1"
Configuration 6: Different Subdomain Policy¶
Configuration 7: Multiple Report Addresses¶
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com,mailto:reports@dmarcanalyzer.com"
Common DMARC Issues¶
Issue 1: DMARC Missing¶
Problem: No DMARC record found
Impact: Most critical security issue (-40 points)
Fix:
Start with p=none and gradually increase enforcement.
Issue 2: DMARC Policy None¶
Problem: DMARC set to p=none (monitoring only)
Impact: No protection (-15 points)
Fix: After monitoring, upgrade to quarantine:
Issue 3: DMARC Policy Quarantine¶
Problem: Not using maximum protection
Impact: Moderate issue (-5 points)
Fix: Upgrade to reject:
Issue 4: No Aggregate Reports¶
Problem: Missing rua= tag
Impact: No visibility (-5 points)
Fix:
Issue 5: Low Percentage¶
Problem: pct= less than 100
Impact: Partial protection (-5 points)
Fix:
Issue 6: DMARC Syntax Error¶
Problem: Invalid DMARC record
Common mistakes:
# Missing v=DMARC1
"p=reject; rua=mailto:dmarc@example.com"
# Wrong version
"v=DMARC2; p=reject"
# Invalid policy
"v=DMARC1; p=block"
# Wrong format
"v=DMARC1; p=reject rua=mailto:dmarc@example.com" # Missing semicolon
Fix: Validate syntax:
Reading DMARC Reports¶
Aggregate Report Analysis¶
Key metrics to monitor:
- Pass Rate
- Goal: 100% of legitimate email passes
-
Action: Investigate any failures
-
Source IPs
- Identify all authorized senders
-
Detect unauthorized senders
-
Volume Trends
- Track email volume over time
-
Detect anomalies
-
Policy Application
- See how receivers handle failures
- Verify policy enforcement
Report Interpretation¶
Good Report (All Pass)¶
Source IP: 192.0.2.1 (Google Workspace)
Count: 1,250 messages
SPF: Pass (1,250)
DKIM: Pass (1,250)
DMARC: Pass (1,250)
Action: None needed ✅
Warning Report (Some Failures)¶
Source IP: 198.51.100.1 (Unknown)
Count: 50 messages
SPF: Fail (50)
DKIM: Fail (50)
DMARC: Fail (50)
Actions: 1. Identify the source 2. If legitimate: Add to SPF, configure DKIM 3. If unauthorized: Monitor for abuse
Critical Report (Spoofing Attempt)¶
Source IP: 203.0.113.1 (Unknown)
Count: 5,000 messages
SPF: Fail (5,000)
DKIM: Fail (5,000)
DMARC: Fail (5,000)
Policy Applied: Reject
Actions: 1. Confirm emails were rejected 2. Document incident 3. Consider abuse report to ISP
DMARC for Different Scenarios¶
Scenario 1: Simple Setup (Google Workspace)¶
# SPF
example.com. IN TXT "v=spf1 include:_spf.google.com -all"
# DKIM (configured in Google Admin)
google._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIj..."
# DMARC
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com"
Scenario 2: Multiple Email Providers¶
# SPF
example.com. IN TXT "v=spf1 include:_spf.google.com include:sendgrid.net -all"
# DKIM
google._domainkey.example.com. IN TXT "v=DKIM1; p=KEY1..."
em123._domainkey.example.com. IN TXT "v=DKIM1; p=KEY2..."
# DMARC
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com"
Scenario 3: No Email Sent¶
# SPF - Reject all
example.com. IN TXT "v=spf1 -all"
# DMARC - Reject
_dmarc.example.com. IN TXT "v=DMARC1; p=reject"
Scenario 4: Subdomains with Third-Party¶
# Main domain - Strict
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; sp=none"
# Marketing subdomain - Separate policy
_dmarc.marketing.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"
DMARC and Email Forwarding¶
Problem: Email forwarding can break SPF alignment.
Why Forwarding Breaks DMARC¶
Original email:
From: user@example.com
MAIL FROM: user@example.com
SPF: Pass + Aligned ✓
DKIM: Pass + Aligned ✓
DMARC: Pass ✓
After forwarding:
From: user@example.com (unchanged)
MAIL FROM: forwarder@gmail.com (changed by Gmail)
SPF: Pass but NOT Aligned ✗
DKIM: Pass + Aligned ✓ (if not modified)
DMARC: Pass ✓ (DKIM saves it!)
DKIM alignment saves forwarded email if body/headers not modified.
Solutions¶
- Use DKIM (not just SPF)
- DKIM survives forwarding better
-
Provides alignment even when SPF fails
-
ARC (Authenticated Received Chain)
- Preserves authentication across forwarding
-
Supported by major providers
-
Relaxed alignment (default)
- More forgiving than strict
- Allows subdomain alignment
Testing DMARC¶
Using ReputeAPI¶
Response:
{
"dmarc": {
"present": true,
"valid": true,
"record": "v=DMARC1; p=reject; rua=mailto:dmarc@example.com",
"policy": "reject",
"subdomain_policy": "none",
"percentage": 100,
"aggregate_reports": ["mailto:dmarc@example.com"]
},
"score": 95,
"issues": []
}
Using Command Line¶
# Query DMARC record
dig _dmarc.example.com TXT +short
# Expected output:
"v=DMARC1; p=reject; rua=mailto:dmarc@example.com"
Online Tools¶
Send Test Email¶
# Send to Gmail and check authentication
echo "Test" | mail -s "DMARC Test" your-gmail@gmail.com
# In Gmail: View Original
# Look for: "DMARC: PASS"
DMARC Best Practices¶
1. Always Use DMARC¶
Even p=none provides visibility.
2. Progress Through Policies¶
Don't rush to reject without monitoring.
3. Set pct=100¶
Full protection, not partial.
4. Enable Aggregate Reports¶
Critical for monitoring and troubleshooting.
5. Use Relaxed Alignment (Default)¶
More compatible with email forwarding and services.
6. Protect Subdomains¶
# Option 1: Same policy
v=DMARC1; p=reject; sp=reject
# Option 2: Separate monitoring
v=DMARC1; p=reject; sp=none
7. Monitor Reports Regularly¶
- Weekly: Check for new sources
- Monthly: Review pass rates
- Always: Investigate failures
8. Document Your Configuration¶
Keep notes on: - Policy progression timeline - Known authorized senders - Report analysis findings
DMARC Validation with ReputeAPI¶
Check DMARC Status¶
import requests
response = requests.get(
"https://api.reputeapi.com/api/v1/check",
params={"domain": "example.com"},
headers={"X-API-Key": "your-api-key"}
)
result = response.json()
# Check DMARC configuration
dmarc = result['dmarc']
if not dmarc['present']:
print("❌ No DMARC record found")
elif dmarc['policy'] == 'none':
print("⚠️ DMARC in monitoring mode only")
elif dmarc['policy'] == 'quarantine':
print("✓ DMARC quarantine policy active")
elif dmarc['policy'] == 'reject':
print("✅ DMARC reject policy active (maximum protection)")
# Check for DMARC issues
dmarc_issues = [i for i in result['issues'] if i['category'] == 'dmarc']
for issue in dmarc_issues:
print(f"\n[{issue['severity']}] {issue['message']}")
print(f"Fix: {issue['remediation']}")
if issue.get('dns_snippet'):
print(f"DNS: {issue['dns_snippet']['value']}")
Monitor DMARC Policy¶
def check_dmarc_policy(domain):
"""Check if domain has strong DMARC policy"""
response = requests.get(
"https://api.reputeapi.com/api/v1/check",
params={"domain": domain},
headers={"X-API-Key": "your-api-key"}
)
dmarc = response.json()['dmarc']
if not dmarc['present']:
return "missing"
elif dmarc['policy'] == 'reject' and dmarc['percentage'] == 100:
return "excellent"
elif dmarc['policy'] == 'quarantine':
return "good"
elif dmarc['policy'] == 'none':
return "monitoring"
else:
return "weak"
Common Questions¶
Do I need both SPF and DKIM for DMARC?¶
No, but recommended. DMARC requires at least ONE aligned authentication: - SPF OR DKIM must pass and align - Best practice: Implement BOTH for redundancy
What if I don't receive DMARC reports?¶
Common reasons:
1. Wrong email format - Must be rua=mailto:email@example.com
2. Email account doesn't exist
3. Reports filtered as spam - Check spam folder
4. No email traffic - Reports only sent if email received
How long until DMARC takes effect?¶
Immediately after DNS propagation (usually 15min-48hrs). However: - Reports are aggregate (daily/weekly) - First report may take 24-48 hours - Full deployment takes 4-8 weeks
Can DMARC break email forwarding?¶
Partially. DMARC can cause issues with: - Email forwarding services - Mailing lists - Auto-forwarding rules
Solution: Use DKIM (survives forwarding better than SPF)
Should I use forensic reports?¶
Usually no: - Few providers send them - Privacy concerns (contain email samples) - Aggregate reports sufficient for most needs
What's a realistic timeline for p=reject?¶
Recommended timeline:
Weeks 1-2: p=none (monitor)
Weeks 3-6: p=quarantine
Weeks 7-8: p=quarantine; pct=100
Weeks 9+: p=reject; pct=100
Total: 2-3 months for safe rollout
Related Concepts¶
- SPF Explained - Sender IP validation
- DKIM Explained - Email signatures
- Email Authentication - Complete framework
- DNS Configuration - Setting up DMARC records
API Resources¶
- GET /api/v1/check - Comprehensive DMARC validation
- POST /api/v1/recommendations - Get DMARC recommendations
- Mailflow Security Score - How DMARC affects your score