Skip to content

Email Security

Chapter 80: Email Security - SPF, DKIM, DMARC

Section titled “Chapter 80: Email Security - SPF, DKIM, DMARC”

Email authentication (SPF, DKIM, DMARC) is critical for email deliverability and security. Without proper configuration, your emails go to spam or can be spoofed. As a DevOps/SRE, you’ll configure these records, monitor authentication failures, and protect your domain from email spoofing.

┌─────────────────────────────────────────────────────────────────────────────┐
│ EMAIL AUTHENTICATION IN DEVOPS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ AUTHENTICATION METHODS │ │
│ │ │ │
│ │ SPF: Authorizes specific IP addresses to send for your domain │ │
│ │ DKIM: Cryptographic signature on email headers │ │
│ │ DMARC: Policy for handling authentication failures │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ DEV OPS TASKS │ │
│ │ │ │
│ │ • Configure SPF DNS record │ │
│ │ • Set up DKIM signing │ │
│ │ • Publish DMARC policy │ │
│ │ • Monitor authentication results │ │
│ │ • Investigate failures │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ DELIVERABILITY IMPACT │ │
│ │ │ │
│ │ Without proper auth: │ │
│ │ • Emails go to spam │ │
│ │ • Domain flagged as suspicious │ │
│ │ • Can be spoofed by attackers │ │
│ │ │ │
│ │ With proper auth: │ │
│ │ • Better inbox placement │ │
│ │ • Protected from spoofing │ │
│ │ • Professional credibility │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘

Real-world DevOps scenarios:

  • AWS SES: Automatic SPF/DKIM when verified
  • Office 365: Requires specific SPF include
  • Google Workspace: DKIM signing with Google default
  • DMARC reports: Analyzing aggregate reports for abuse

┌─────────────────────────────────────────────────────────────────────────┐
│ SPF FLOW │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 1. Sender domain publishes SPF record in DNS │ │
│ │ 2. Receiving server queries SPF record │ │
│ │ 3. Checks if sender IP is authorized │ │
│ │ 4. Returns Pass/Fail/SoftFail/Neutral/Fail │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ DNS Record Format: │
│ v=spf1 ip4:192.0.2.0/24 include:_spf.google.com ~all │
│ │
│ Mechanisms: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ +all Pass all (production) │ │
│ │ ~all SoftFail (testing) │ │
│ │ -all Fail (strict) │ │
│ │ ?all Neutral │ │
│ │ mx Authorized MX servers │ │
│ │ a Authorized A records │ │
│ │ include Include another domain's SPF │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Terminal window
# DNS TXT Record Examples
# Simple - only MX servers can send
example.com. IN TXT "v=spf1 mx -all"
# With Google Workspace
example.com. IN TXT "v=spf1 include:_spf.google.com ~all"
# Multiple sources
example.com. IN TXT "v=spf1 ip4:203.0.113.0/24 mx -all"
# Include multiple providers
example.com. IN TXT "v=spf1 include:_spf.google.com include:_spf.office365.com -all"
# With all mechanisms
example.com. IN TXT "v=spf1 mx a:mail.example.com ip4:203.0.113.0/24 -all"

┌─────────────────────────────────────────────────────────────────────────┐
│ DKIM FLOW │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 1. Domain generates public/private key pair │ │
│ │ 2. Public key published in DNS ( TXT record) │ │
│ │ 3. Outgoing mail signed with private key │ │
│ │ 4. Receiving server fetches DKIM key from DNS │ │
│ │ 5. Verifies signature │ │
│ │ 6. Result: Pass/Fail/None │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ DKIM Header: │
│ DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; │
│ d=example.com; s=mail; h=from:to:subject; │
│ bh=...; b=... │
│ │
│ Selector (s=mail): Multiple DKIM keys per domain │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Terminal window
# Install
sudo apt install opendkim opendkim-tools
# Generate key
sudo opendkim-genkey -s mail -d example.com -D /etc/opendkim/keys/
# Configure /etc/opendkim.conf
KeyTable /etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
# /etc/opendkim/KeyTable
mail._domainkey.example.com example.com:mail:/etc/opendkim/keys/mail.private
# /etc/opendkim/SigningTable
*@example.com mail._domainkey.example.com
# /etc/opendkim/TrustedHosts
127.0.0.1
*.example.com
# Postfix integration
# /etc/postfix/main.cf
smtpd_milters = inet:localhost:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept
# Create systemd service for OpenDKIM

80.3 DMARC (Domain-based Message Authentication)

Section titled “80.3 DMARC (Domain-based Message Authentication)”
┌─────────────────────────────────────────────────────────────────────────┐
│ DMARC FLOW │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Builds on SPF and DKIM: │ │
│ │ - Requires at least one to pass (or both) │ │
│ │ - Alignment check (From domain matches SPF/DKIM) │ │
│ │ - Policy enforcement │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ Policy Options: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ p=none | Monitor only, no action taken │ │
│ │ p=quarantine| Mark as spam │ │
│ │ p=reject | Reject messages completely │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ Alignment: │
│ - relaxed: Domain match (subdomains OK) │
│ - strict: Exact domain match required │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Terminal window
# Basic DNS TXT Record
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"
# Full example
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; sp=reject; \
rua=mailto:dmarc@example.com; \
ruf=mailto:forensic@example.com; \
pct=100; \
adkim=r; aspf=r"
# Parameters:
# v=DMARC1 - Version
# p= - Policy (none/quarantine/reject)
# sp= - Subdomain policy
# pct - Percentage of messages to apply
# rua - Aggregate reports (mailto)
# ruf - Forensic reports (mailto)
# adkim - DKIM alignment (relaxed/strict)
# aspf - SPF alignment (relaxed/strict)

Terminal window
# Check DNS records
dig TXT example.com
dig TXT _dmarc.example.com
nslookup -type=txt example.com
# Check SPF
nslookup -type=txt _spf.example.com
# Check DKIM
nslookup -type=txt mail._domainkey.example.com
# Online testing tools
# https://www.mail-tester.com/
# https://www.dmarcanalyzer.com/
# https://dkimvalidator.com/
# https://www.g Mass MXToolbox
# Check email headers
# Look for:
# Authentication-Results: SPF=pass, DKIM=pass, DMARC=pass

┌─────────────────────────────────────────────────────────────────────────┐
│ EMAIL SECURITY INTERVIEW QUESTIONS │
├─────────────────────────────────────────────────────────────────────────┤
Q1: What does SPF verify? │
A1: │
- Verifies that the sending mail server is authorized by the domain │
- Checks if sender IP is in the SPF DNS record │
- Returns: Pass, Fail, SoftFail, Neutral, None │
─────────────────────────────────────────────────────────────────────────┤
Q2: What does DKIM verify? │
A2: │
- Verifies email hasn't been tampered with in transit │
- Cryptographic signature in email header │
- Public key in DNS (TXT record) │
- Result: Pass, Fail, None │
─────────────────────────────────────────────────────────────────────────┤
Q3: What does DMARC do? │
A3: │
- Builds on SPF and DKIM │
- Aligns From domain with SPF/DKIM domains │
- Provides policy (none/quarantine/reject) │
- Enables reporting (aggregate and forensic) │
─────────────────────────────────────────────────────────────────────────┤
Q4: What is the difference between ~all and -all in SPF? │
A4: │
- ~all (SoftFail): Non-matching servers accepted but marked │
- -all (Fail): Strict - reject non-authorized servers │
- Start with ~all, then move to -all after testing │
─────────────────────────────────────────────────────────────────────────┤
Q5: What is DKIM alignment? │
A5: │
- Domain in From: header must match d= in DKIM signature │
- relaxed: subdomains OK │
- strict: exact match required │
- Prevents domain spoofing │
─────────────────────────────────────────────────────────────────────────┤
Q6: How do you implement email authentication? │
A6: │
1. SPF: Add TXT record to DNS │
2. DKIM: Generate key pair, configure mail server, add DNS record │
3. DMARC: Add TXT record to _dmarc subdomain │
4. Monitor reports and adjust policies │
─────────────────────────────────────────────────────────────────────────┤
Q7: What are DMARC aggregate (rua) and forensic (ruf) reports? │
A7: │
- rua: Aggregate reports - daily summary of auth results │
- ruf: Forensic reports - immediate notice of failures │
- Both sent to specified mailto addresses │
─────────────────────────────────────────────────────────────────────────┤
Q8: What is email deliverability? │
A8: │
- Ability to land in inbox, not spam │
- Depends on: SPF, DKIM, DMARC, sender reputation, content │
- Use mail-tester.com to check score │
─────────────────────────────────────────────────────────────────────────┤
Q9: What is a selector in DKIM? │
A9: │
- Selector (s=) allows multiple DKIM keys per domain │
- mail._domainkey for primary key │
- Allows key rotation without DNS changes │
─────────────────────────────────────────────────────────────────────────┤
Q10: How do you troubleshoot email authentication failures? │
A10: │
1. Check DNS records are published correctly │
2. Use dig/online tools to verify records │
3. Check email headers for auth results │
4. Review DMARC reports │
5. Verify alignment (From matches d=) │
└─────────────────────────────────────────────────────────────────────────┘

WRONG:

Terminal window
# Too many includes - can exceed DNS lookup limit
v=spf1 include:_spf.google.com include:amazonses.com include:mailchimp.com include:sendgrid.com include:another-service.com -all

CORRECT:

Terminal window
# Consolidate to reduce lookups
# Use ~all initially, move to -all after testing
v=spf1 include:_spf.google.com include:amazonses.com -all

Why: SPF has a 10 DNS lookup limit. Exceeding it causes SPF to fail permanently ( PermError ).


2. Setting DMARC Policy to ‘reject’ Without Testing

Section titled “2. Setting DMARC Policy to ‘reject’ Without Testing”

WRONG:

Terminal window
# Jump straight to reject - will block legitimate email
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com"

CORRECT:

Terminal window
# Phase 1: Monitor only
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com"
# Phase 2: Quarantine
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"
# Phase 3: Reject (after 2-4 weeks of monitoring)
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com"

Why: Reject policy immediately bounces all failing messages. Must ensure 100% alignment first.


WRONG:

Terminal window
# No reporting - blind to issues
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; pct=100"

CORRECT:

Terminal window
# Always set up reporting
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine;
rua=mailto:dmarc-aggregate@example.com;
ruf=mailto:dmarc-forensic@example.com"

Why: DMARC reports reveal authentication issues, domain abuse, and legitimate sending sources you may not know about.


WRONG:

Terminal window
# Too small - vulnerable to attacks
mail._domainkey IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEF..."

CORRECT:

Terminal window
# 2048-bit minimum, 4096-bit recommended
mail._domainkey IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA... (longer key)"

Why: 1024-bit RSA keys are considered insecure. Use at least 2048-bit keys.


5. Not Implementing SPF, DKIM, and DMARC Together

Section titled “5. Not Implementing SPF, DKIM, and DMARC Together”

WRONG:

Terminal window
# Only SPF - missing layers of protection
v=spf1 mx -all
# No DKIM
# No DMARC

CORRECT:

Terminal window
# SPF: Authorizes sending servers
v=spf1 mx include:_spf.google.com -all
# DKIM: Cryptographic signature
mail._domainkey IN TXT "v=DKIM1; k=rsa; p=..."
# DMARC: Policy and reporting
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"

Why: Each provides different protection. SPF verifies sender IP, DKIM verifies message integrity, DMARC enforces policy.


WRONG:

Terminal window
# Main domain protected but subdomains vulnerable
_dmarc.example.com. IN TXT "v=DMARC1; p=reject"
_dmarc.marketing.example.com. IN TXT "v=DMARC1; p=none"

CORRECT:

Terminal window
# Apply subdomain policy
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; sp=reject"

Why: Attackers often spoof subdomains (e.g., security@example.com) to bypass main domain protection.


WRONG:

Terminal window
# Same DKIM key for years
mail._domainkey IN TXT "v=DKIM1; k=rsa; p=... (old key)"

CORRECT:

Terminal window
# Key rotation every 6-12 months
# Add new selector before removing old
mail._domainkey IN TXT "v=DKIM1; k=rsa; p=2024-key..."
mail2023._domainkey IN TXT "v=DKIM1; k=rsa; p=2023-key..."

Why: Regular key rotation limits exposure if a key is compromised. Use selectors for version management.


Terminal window
# SPF
v=spf1 mx -all
# DKIM
# Public key in DNS: mail._domainkey.example.com
# Sign outgoing mail with private key
# DMARC
v=DMARC1; p=reject; rua=mailto:dmarc@example.com

  • SPF: Verifies sending server is authorized
  • DKIM: Cryptographic signature verifying email integrity
  • DMARC: Combines SPF/DKIM with policy and reporting

Chapter 81: Kernel Compilation


Last Updated: February 2026