Many developers discover this troubling scenario after setting up SPF records:
Received-SPF: fail (google.com: domain of info@yourdomain.com does not designate 23.249.225.236 as permitted sender)
Authentication-Results: mx.google.com;
spf=fail (google.com: domain of info@yourdomain.com does not designate 23.249.225.236 as permitted sender) smtp.mailfrom=info@yourdomain.com
Yet the message still lands in recipients' inboxes. This happens because SPF alone doesn't enforce message rejection - it merely provides authentication information.
Major providers like Gmail evaluate multiple factors when deciding whether to deliver a message:
- SPF verification (checking IP against authorized senders)
- DKIM signature validation
- Content analysis and spam scoring
- User-specific filters
Even with SPF failures, messages might still be delivered if other signals are positive.
DMARC (Domain-based Message Authentication, Reporting & Conformance) tells receivers what to do with messages that fail SPF or DKIM checks. A basic DMARC record looks like:
v=DMARC1; p=reject; rua=mailto:reports@yourdomain.com; ruf=mailto:forensics@yourdomain.com
Key components for developers to implement:
_dmarc.yourdomain.com. IN TXT "v=DMARC1; p=reject; pct=100; rua=mailto:dmarc-reports@yourdomain.com; ruf=mailto:dmarc-forensics@yourdomain.com; sp=reject; adkim=s; aspf=s"
For domains using Google Workspace, complete setup requires:
; SPF Record
yourdomain.com. IN TXT "v=spf1 include:_spf.google.com ~all"
; DMARC Record
_dmarc.yourdomain.com. IN TXT "v=DMARC1; p=quarantine; pct=100; rua=mailto:dmarc-reports@yourdomain.com"
Monitor reports before moving to "p=reject" policy.
DMARC aggregate reports (sent to your rua address) use XML format:
<feedback>
<report_metadata>
<org_name>google.com</org_name>
<email>noreply-dmarc-support@google.com</email>
<report_id>20231125133700.12345</report_id>
<date_range>
<begin>1700863200</begin>
<end>1700949599</end>
</date_range>
</report_metadata>
<policy_published>
<domain>yourdomain.com</domain>
<adkim>r</adkim>
<aspf>r</aspf>
<p>none</p>
<sp>none</sp>
<pct>100</pct>
</policy_published>
</feedback>
Use these command-line tools to verify your setup:
# Check SPF record
dig +short txt yourdomain.com
# Check DMARC record
dig +short txt _dmarc.yourdomain.com
# Send test email with SPF fail
swaks --to recipient@gmail.com --from spoofed@yourdomain.com --server mail.provider.net
For complete protection, implement DKIM signing. Example using OpenDKIM:
# /etc/opendkim.conf
Domain yourdomain.com
KeyFile /etc/opendkim/keys/yourdomain.com/default.private
Selector default
# Generate DKIM key
opendkim-genkey -b 2048 -d yourdomain.com -s default -D /etc/opendkim/keys/yourdomain.com
Add the generated public key to your DNS:
default._domainkey.yourdomain.com. IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC..."
Many developers assume that implementing SPF (Sender Policy Framework) is enough to prevent email spoofing. However, as you've discovered with services like deadfake.com, this isn't the case. Let's examine why:
Received-SPF: fail (google.com: domain of info@yourdomain.com does not designate 23.249.225.236 as permitted sender)
Authentication-Results: mx.google.com;
spf=fail (google.com: domain of info@yourdomain.com does not designate 23.249.225.236 as permitted sender) smtp.mailfrom=info@yourdomain.com
SPF alone is like locking your front door but leaving the windows open. The solution is implementing DMARC (Domain-based Message Authentication, Reporting & Conformance). Here's how to set it up:
_dmarc.yourdomain.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc-reports@yourdomain.com; ruf=mailto:dmarc-forensics@yourdomain.com; pct=100"
DMARC offers three policy levels you can implement:
- p=none: Monitor only mode (good for initial testing)
- p=quarantine: Send suspicious emails to spam/junk
- p=reject: Block unauthorized emails completely
Here's how to combine SPF and DMARC for common scenarios:
# For domains using Google Workspace
yourdomain.com. IN TXT "v=spf1 include:_spf.google.com -all"
_dmarc.yourdomain.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc-reports@yourdomain.com"
# For domains with multiple email providers
yourdomain.com. IN TXT "v=spf1 include:_spf.google.com include:servers.mcsv.net -all"
_dmarc.yourdomain.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@yourdomain.com"
Once implemented, you'll start receiving XML reports. Here's a Python snippet to parse them:
import xml.etree.ElementTree as ET
import gzip
from io import BytesIO
def parse_dmarc_report(report_file):
with gzip.open(report_file, 'rb') as f:
xml_data = BytesIO(f.read())
root = ET.parse(xml_data).getroot()
report_metadata = root.find('report_metadata')
policy_published = root.find('policy_published')
print(f"Organization: {report_metadata.find('org_name').text}")
print(f"Domain: {policy_published.find('domain').text}")
print(f"Policy: {policy_published.find('p').text}")
Use these tools to verify your setup:
- MXToolbox DMARC Analyzer
- Google Admin Toolbox Checker
- Dmarcian Domain Checker
Remember to start with p=none and gradually move to p=reject after monitoring legitimate traffic patterns.