Why SPF Alone Fails Against Email Spoofing: Implementing DMARC for Gmail Delivery Fix


2 views

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.