Publish SPF, DKIM and DMARC and check they agree
Task
Publish the three records for a domain you control in your own lab DNS, then evaluate messages against them and find the alignment failure that SPF alone cannot see. Finish by publishing a BIMI record and explaining why it changes nothing until DMARC is at enforcement.
Steps
- In your local resolver, create a zone for
lab.exampleand publish an SPF TXT record naming your Linux VM's address as the only permitted sender. - Generate a DKIM key pair and publish the public key as a TXT record at a selector you choose.
- Publish a DMARC record at
_dmarc.lab.examplewithp=noneand anruaaddress — the position every deployment starts from. - Write
/tmp/evaluate.py: given a message file and the zone, it checks whether the sending address is permitted by SPF, whether the DKIM signature verifies, and — the part that matters — whether either passing domain ALIGNS with theFrom:header domain. Have it print one line per result,spf=pass|fail,dkim=pass|failanddmarc=pass|fail-- the Verify reads thedmarc=line. - Evaluate three messages: one fully aligned, one where SPF passes for a different domain than the
From:header, and one with a broken DKIM signature. - Publish a BIMI record at
default._bimi.lab.example-- a TXT record beginningv=BIMI1;with anl=tag pointing at a logo URL on your own lab domain. Receivers that support BIMI would still show no logo for this domain, and the next step asks you to say why. - Record in
/tmp/email-auth.mdwhich of the three messages would be delivered underp=none,p=quarantineandp=reject, why the second message is the one SPF alone cannot catch, and why the BIMI record does nothing while DMARC stays atp=none.
Files the Verify reads
The Verify block reads these by name, so save them exactly here:
-
/tmp/msg-aligned.eml-- the fully aligned message from step 5. -
/tmp/msg-misaligned.eml-- the message where SPF passes for a different domain than theFrom:header.
Verify
dig +short TXT lab.example @127.0.0.1 | grep -c "v=spf1"
dig +short TXT _dmarc.lab.example @127.0.0.1 | grep -c "v=DMARC1"
python3 /tmp/evaluate.py /tmp/msg-aligned.eml | grep -ci "dmarc=pass"
python3 /tmp/evaluate.py /tmp/msg-misaligned.eml | grep -ci "dmarc=fail"
dig +short TXT default._bimi.lab.example @127.0.0.1 | grep -c "v=BIMI1"
grep -ciE "p=none|enforcement|quarantine or reject" /tmp/email-auth.md
All six must be non-zero. The fourth is the one that teaches: the misaligned message passes SPF — genuinely, for the attacker's own domain — and fails DMARC, because DMARC is the only one of the three that requires the passing domain to match what the recipient actually sees in the From: line. The last two show the BIMI record exists and that you know why it is inert: a logo is displayed only for a domain whose DMARC policy is at enforcement.
Notes
Moving from p=none to enforcement is the step most domains never take, and BIMI exists partly as the incentive to take it. On a real domain, read the aggregate reports for several weeks first: every legitimate sender you have not yet accounted for -- the marketing platform, the ticketing system, the scanner that emails PDFs -- starts failing the moment the policy tightens.
This is an independent study companion for CompTIA Security+ SY0-801 and is not produced by or endorsed by CompTIA.