Privacy Tools Guide

Email spoofing remains one of the most common attack vectors used by malicious actors. When someone sends emails that appear to originate from your domain, they can phishing your users, damage your sender reputation, and compromise communications with your customers. Configuring proper email authentication records—SPF, DKIM, and DMARC—provides defense-in-depth against these threats.

This guide walks through setting up each protocol with practical examples you can implement immediately.

Understanding the Three Pillars of Email Authentication

Email authentication works through three complementary mechanisms. Sender Policy Framework (SPF) authorizes specific mail servers to send email on behalf of your domain. DomainKeys Identified Mail (DKIM) adds a cryptographic signature to outgoing messages. Domain-based Message Authentication, Reporting, and Conformance (DMARC) ties both together with policy enforcement and reporting.

Each protocol addresses different attack vectors. SPF prevents unauthorized servers from sending mail. DKIM ensures message integrity during transit. DMARC provides visibility into who’s attempting to send mail from your domain and instructs receivers what to do with unauthenticated messages.

Configuring SPF (Sender Policy Framework)

SPF works through DNS TXT records that list authorized sending sources for your domain. When a receiving mail server receives a message, it checks if the connecting server is authorized according to your SPF record.

Basic SPF Record

For a domain that sends email through a single provider like Google Workspace:

v=spf1 include:_spf.google.com ~all

This record specifies version 1, includes Google’s SPF information, and uses a soft fail (~all) for non-listed servers. The soft fail tells receivers to treat unauthorized messages as suspicious but not necessarily reject them.

SPF for Multiple Providers

If you use multiple email services—perhaps Google Workspace for business email and SendGrid for transactional mail—include both:

v=spf1 include:_spf.google.com include:sendgrid.net ~all

SPF for Marketing Platforms

When using marketing tools that send email on your behalf, add their servers:

v=spf1 include:_spf.google.com include:servers.mcsv.net include:sendgrid.net ~all

Avoid including more than 10 DNS lookups in your SPF record, as some receivers reject records that exceed this limit. Use the -all (hard fail) only after thoroughly testing with ~all.

Setting Up DKIM (DomainKeys Identified Mail)

DKIM adds a digital signature to email headers using public-key cryptography. Your mail server signs outgoing messages with a private key, and receiving servers verify the signature using the public key published in your DNS.

Generating DKIM Keys

Most email providers handle DKIM key generation for you. For self-hosted mail servers, generate a 2048-bit key pair using OpenSSL:

openssl genrsa -out dkim_private.pem 2048
openssl rsa -in dkim_private.pem -pubout -out dkim_public.pem

DKIM DNS Record Format

Publish the public key as a CNAME or TXT record. The selector identifies which key to use:

selector1._domainkey.yourdomain.com IN TXT "v=DKIM1; k=rsa; p=YOUR_PUBLIC_KEY_HERE"

Replace YOUR_PUBLIC_KEY_HERE with the base64-encoded public key, removing line breaks and headers. Most providers give you the complete record to copy.

Testing DKIM Setup

Send a test email to a verification service or check the email headers:

# Send test email and check headers
dig +short TXT selector1._domainkey.yourdomain.com

Look for the DKIM-Signature header in received emails. A valid signature shows d=yourdomain.com and s=selector.

Implementing DMARC (Domain-based Message Authentication)

DMARC builds on SPF and DKIM by defining an authentication policy and enabling reporting. A DMARC record tells receivers how to handle messages that fail authentication and provides visibility into authentication results.

Basic DMARC Record

_dmarc.yourdomain.com IN TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@yourdomain.com"

This minimal record uses policy none (take no action on failures) and sends aggregate reports to the specified email address. Start with none to gather data before enforcing stricter policies.

Monitoring Phase

Deploy DMARC with p=none for several weeks. Review the aggregate reports to understand:

Enforcement Phase

After identifying all legitimate sources, move to enforcement:

_dmarc.yourdomain.com IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@yourdomain.com; ruf=mailto:dmarc-forensics@yourdomain.com"

The quarantine policy directs receivers to mark failed messages as spam. Use p=reject only after confirming all legitimate mail streams authenticate properly—rejecting mail can cause legitimate messages to bounce.

DMARC Report Aggregation

DMARC reports arrive as XML attachments. Parse them to extract:

# Simple XML parsing for DMARC reports
import xml.etree.ElementTree as ET

def parse_dmarc_report(xml_data):
    root = ET.fromstring(xml_data)
    for feedback in root.findall('.//feedback'):
        for record in feedback.findall('.//record'):
            source_ip = record.find('.//source_ip').text
            disposition = record.find('.//policy_evaluated/disposition').text
            dkim_result = record.find('.//policy_evaluated/dkim').text
            spf_result = record.find('.//policy_evaluated/spf').text
            print(f"IP: {source_ip}, Action: {disposition}, DKIM: {dkim_result}, SPF: {spf_result}")

Automated report processing helps identify spoofing attempts and misconfigured sending services quickly.

Common Pitfalls and Troubleshooting

SPF Alignment Issues

SPF checks require alignment between the envelope-from and header-from domains. If your marketing platform sends from emails.yourdomain.com but your website shows yourdomain.com in the From header, alignment fails. Use spf=aligned in your DMARC record or ensure consistent domain usage.

DKIM Key Rotation

Rotate DKIM keys periodically—typically annually for 2048-bit keys. Schedule key rotation during low-traffic periods and maintain both old and new keys during the transition to avoid delivery disruptions.

Third-Party Senders

Every service sending email on your behalf must be included in your SPF record. Common oversights include:

Document all email-sending services and update SPF records whenever adding new tools.

Verification and Deployment Checklist

Before going live with DMARC enforcement:

This systematic approach minimizes the risk of legitimate mail being blocked during the enforcement phase.

BIMI (Brand Indicators for Message Identification)

BIMI is an emerging standard that combines DMARC alignment with visual authentication. When properly configured, your brand logo appears alongside emails in supported clients:

default._bimi.yourdomain.com IN TXT "v=BIMI1; l=https://yourdomain.com/logo.svg; a=self;"

BIMI requires:

Benefits and Implementation

BIMI increases email deliverability and user trust. Recipients see your verified logo alongside messages, making phishing attacks harder to execute:

# Create BIMI-compliant logo
# Requirements:
# - SVG format
# - 200x200px or larger
# - Hosted on HTTPS
# - Accessible from yourdomain.com

curl -v https://yourdomain.com/logo.svg | head -50

Email Authentication Monitoring and Analysis

Automated analysis of authentication results helps identify configuration issues:

#!/usr/bin/env python3
"""Analyze DMARC report data for authentication insights"""

import xml.etree.ElementTree as ET
from collections import defaultdict

def analyze_dmarc_report(xml_file):
    """Extract authentication metrics from DMARC report"""
    tree = ET.parse(xml_file)
    root = tree.getroot()

    results = defaultdict(lambda: {
        'spf_pass': 0, 'spf_fail': 0,
        'dkim_pass': 0, 'dkim_fail': 0,
        'dmarc_pass': 0, 'dmarc_fail': 0
    })

    for record in root.findall('.//record'):
        ip = record.find('.//source_ip').text
        spf = record.find('.//policy_evaluated/spf').text
        dkim = record.find('.//policy_evaluated/dkim').text
        dmarc = record.find('.//policy_evaluated/disposition').text

        if spf == 'pass':
            results[ip]['spf_pass'] += 1
        else:
            results[ip]['spf_fail'] += 1

        if dkim == 'pass':
            results[ip]['dkim_pass'] += 1
        else:
            results[ip]['dkim_fail'] += 1

        if dmarc == 'pass':
            results[ip]['dmarc_pass'] += 1

    return results

# Generate summary
data = analyze_dmarc_report('dmarc_report.xml')
for ip, metrics in sorted(data.items()):
    total = metrics['spf_pass'] + metrics['spf_fail']
    spf_rate = (metrics['spf_pass'] / total * 100) if total > 0 else 0
    print(f"IP {ip}: SPF {spf_rate:.1f}% pass rate")

Subdomain DMARC Policies

Organizations with many subdomains need strategic DMARC policies:

# Parent domain policy
_dmarc.yourdomain.com IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com"

# Subdomain-specific policy (overrides parent)
_dmarc.mail.yourdomain.com IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com"

# Development subdomain with minimal restrictions
_dmarc.dev.yourdomain.com IN TXT "v=DMARC1; p=none; rua=mailto:dmarc-dev@yourdomain.com"

Troubleshooting Authentication Failures

When emails fail authentication despite proper configuration:

# Debug SPF failures
dig yourdomain.com txt | grep spf

# Check for SPF syntax errors
python3 -c "
import spf
results = spf.query('192.0.2.1', 'user@yourdomain.com', 'mail.yourdomain.com')
print(f'SPF Result: {results[0]} - {results[2]}')
"

# Test DKIM signature
echo "test" | openssl dgst -sha256 -sign dkim_private.pem | openssl enc -base64

Email Authentication for Different Service Types

Different service categories have unique authentication requirements:

Marketing Emails

Marketing platforms like Mailchimp require SPF includes. Their servers send on your behalf:

v=spf1 include:mailchimp.com include:_spf.google.com ~all

Transactional Emails

Transactional email services (SendGrid, AWS SES) need dedicated DKIM keys:

# SendGrid DKIM setup
sendgrid._domainkey.yourdomain.com IN CNAME sendgrid.net

Password Reset and Notification Emails

Internal services sending from your domain should use your own DKIM key:

# Internal service example: app.yourdomain.com
# Configure to sign with your domain's DKIM key
# Don't create separate keys for each subdomain

DMARC Forensic Reports

Forensic reports (ruf) provide detailed information about failed messages:

_dmarc.yourdomain.com IN TXT "v=DMARC1; p=quarantine; ruf=mailto:forensics@yourdomain.com"

Processing forensic reports automatically:

#!/usr/bin/env python3
"""Process DMARC forensic reports for detailed failure analysis"""

import email
import gzip
import io
from email import policy

def process_forensic_report(message_bytes):
    """Extract forensic report from DMARC email"""
    msg = email.message_from_bytes(message_bytes, policy=policy.default)

    for part in msg.iter_parts():
        if part.get_content_type() == 'application/gzip':
            # Decompress gzipped XML
            compressed = part.get_payload(decode=True)
            xml_data = gzip.decompress(compressed)

            print("Forensic report contents:")
            print(xml_data.decode('utf-8')[:500])  # First 500 chars

Email Authentication Best Practices Summary

Implementation Checklist

Built by theluckystrike — More at zovo.one