Skip to main content

Email Authentication: Build SPF, DKIM and DMARC, Then Break Them

Run a mail server on your laptop, send messages into it, and work out by hand why receivers accept or reject them. You sign a message with DKIM, change one character, and watch the signature fail. You separate the envelope sender from the From header the reader sees, which is the whole point of DMARC alignment. Then you send through a provider and compare its headers with the ones you built yourself.

intermediate
container
Networking
80 minutes
7 steps
Prerequisites
  • Docker installed and running
  • Python 3.9 or newer
  • Comfortable reading DNS records with dig
  • A domain you control, for the last step only
Learning Objectives
  • Tell the envelope sender apart from the From header, and explain why receivers check both
  • Read an SPF record and say which IPs it authorises
  • Sign a message with DKIM and verify the signature offline
  • Show that changing one byte of a signed message breaks its DKIM signature
  • Explain how DMARC alignment ties SPF and DKIM to the address the reader sees
  • Read the Authentication-Results header a real receiver writes
Technologies Used
SMTP
DNS
DKIM
SPF
DMARC
Docker
Python
Exercise Steps
1

Catch Mail on Your Own Machine

Current

Before you can reason about why a message is rejected, you need to see what is actually sent. Mailpit is a mail server that accepts anything on port 1025 and shows it in a web UI on port 8025. Nothing leaves your machine, so you can send whatever you like. swaks is the SMTP equivalent of curl: it speaks the protocol one command at a time and prints both sides of the conversation.

2

Two Different From Addresses

Every message carries two sender addresses. The envelope sender is given in the SMTP MAIL FROM command and is what bounces go back to. The From header is inside the message and is what the mail client shows the reader. Nothing in SMTP requires them to match. This gap is why email spoofing works at all, and every authentication standard that follows exists because of it.

3

Read an SPF Record and Say What It Authorises

SPF is a TXT record listing which IP addresses may send mail for a domain. The receiver takes the envelope sender's domain, looks up that record, and checks the IP that connected against it. It says nothing about the From header, and nothing about the message body. Reading real records is the fastest way to see the shape of it.

4

Sign a Message with DKIM

DKIM signs chosen headers and the body with a private key. The receiver fetches the public key from DNS and checks the signature. Because it travels inside the message, it survives forwarding, and because it covers the body, it proves the content was not changed on the way. You will generate a key, sign a message, and verify it without any DNS at all.

5

Change One Character and Watch It Fail

A signature you have never seen fail is a signature you are trusting on faith. Change a single character of the signed body and verify again. This is also the quickest way to understand a class of real incidents: anything in the delivery path that rewrites a message, such as a mailing list appending a footer or a gateway rewriting links, invalidates the signature in exactly this way.

6

DMARC: Tying the Checks to the Address the Reader Sees

SPF checks the envelope. DKIM checks a signing domain. Neither has anything to say about the From header, which is the only address most readers ever look at. DMARC closes that gap. It requires at least one of SPF or DKIM to pass and to be aligned with the From domain, and it tells receivers what to do when nothing is. Go back to the spoof you sent in step two and work out what DMARC would have done with it.

7

Compare Your Headers with a Provider's

You have now done by hand what a sending provider does for every message. The last step is to see the finished article. Send one message through a provider that handles SPF, DKIM and DMARC alignment for you, then read the Authentication-Results header the receiving side writes. That header is the receiver's verdict, and it is the thing to check first whenever mail is going missing.

Found an issue?

More exercises

Also worth your time on this topic