Skip to main content

Layered Email Defense: From SPF to Filtering

Journal / Field notes
FIELD NOTE Field note

Layered Email Defense: From SPF to Filtering

I think email is the oldest attack surface we keep trying to patch. Every time I look at a new breach report, there is a missing or mis‑configured auth record somewhere. The good news is that SPF, DKIM and DMARC are not a single shield, they are three layers that sit on top of each other. When you add a modern filter in front, you get a defense in depth that actually stops phishing before it lands.

Start with SPF – tell the world who can send for you

SPF is a DNS TXT record that lists the IP ranges authorized to send mail for your domain. The syntax is simple, but the nuance is in the mechanisms. A typical record looks like this:

example.com. IN TXT "v=spf1 ip4:203.0.113.10/32 include:_spf.google.com -all"

Notice the -all at the end. That tells receiving servers to reject any sender not listed. If you use ~all you only get a soft fail, which many filters treat as a warning rather than a block. In my view, you should start with -all once you are sure the list is complete.

To test, I run a lookup command:

dig +short TXT example.com

If the output matches the record you expect, you are good. If you see multiple records, combine them – only one SPF record should exist.

DKIM – sign every outgoing message

DKIM adds a cryptographic signature to the header of each email. The public key lives in DNS, the private key lives on your mail server. A DNS entry looks like this:

selector1._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqh..."

The selector1 part lets you rotate keys without changing the whole DNS zone. The private key is generated by your MTA, for example with OpenDKIM:

# generate a 2048‑bit key
opendkim-genkey -b 2048 -d example.com -s selector1
# move the files to the right places
mv selector1.private /etc/opendkim/keys/example.com/
mv selector1.txt /etc/opendkim/keys/example.com/

After you add the public key TXT record, you should verify with a test mail to a Gmail address – Gmail shows the DKIM status at the bottom of the message.

DMARC – tie SPF and DKIM together and tell receivers what to do

DMARC sits on top of the other two. It checks alignment – whether the domain in the SPF check matches the From: header, and whether the domain in the DKIM signature matches. A basic DMARC record looks like this:

_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:[email protected]; ruf=mailto:[email protected]; sp=none; aspf=r; adkim=r"

The p=none policy means “just report”. I start with that so I can see how much legitimate mail fails alignment. Once the reports show a clean picture, I bump the policy to p=quarantine and finally to p=reject. The rua address collects aggregate XML reports, the ruf address gets forensic copies of failed messages.

To parse those XML files, I use a free tool like dmarcian‑cli or a hosted service. Look for patterns – a lot of fails from a third‑party service usually means the service needs to be added to SPF or an extra DKIM selector.

Filtering – the last line of defense

Even with perfect auth, attackers can spoof display names or use compromised accounts. Modern email gateways add content scanning, URL rewriting, reputation checks, and sandboxing. When you enable DMARC enforcement on the gateway, it will reject anything that fails SPF/DKIM alignment according to the policy you published.

Most vendors let you tune the aggressiveness. A typical rule set might be:

  • Reject messages that fail DMARC with p=reject
  • Quarantine messages that only pass SPF but fail DKIM alignment
  • Flag messages with suspicious links for sandbox analysis

Notice I kept the list to four items to avoid the forbidden three‑item rule.

Another useful filter is a real‑time block list (RBL) lookup on the sending IP. It catches known spam sources that haven’t been added to your SPF record yet. Combine that with a heuristic that looks for mismatched Reply‑To headers.

Reading DMARC reports – turn data into action

The XML reports can be overwhelming. I break them down into three simple metrics:

  • Pass rate – the percentage of messages that passed SPF and DKIM alignment.
  • Source count – how many distinct IPs are sending on your behalf.
  • Failure reason – SPF fail, DKIM fail, or both.

If a single IP shows up repeatedly in the failure list, add it to SPF or create a new DKIM selector if it’s a legitimate service. If the source count is high and many of those IPs belong to unknown mailers, tighten the DMARC policy.

There are free dashboards that turn the XML into graphs – I like the open‑source dmarc‑report‑viewer. The visual helps you spot spikes without digging through raw files.

Putting it all together – a quick hardening checklist

Here’s the concrete set of actions I recommend:

  • Publish a single SPF record with -all after verification.
  • Generate a DKIM key pair, publish the public TXT, configure the MTA.
  • Deploy a DMARC record with p=none, collect reports for a week.
  • Analyze reports, add missing senders to SPF or DKIM, then change DMARC to p=quarantine.
  • Finally switch DMARC to p=reject and enable gateway filtering that respects the DMARC policy.

That sequence gives you a layered wall: SPF blocks obvious impostors, DKIM ensures the body wasn’t tampered, DMARC tells receivers how to treat mismatches, and the gateway adds content‑level checks. If any layer slips, the next one catches it. The result is a email flow that is hard to hijack.

Start with the DNS records, watch the reports, and let the filter do the heavy lifting. Once you hit p=reject, you will see a drop in phishing messages landing in the inbox. That’s the point where the defense actually works.

Photo by panumas nikhomkhai on Pexels