SPF, DKIM and DMARC for one small domain
2026-06-27
Three records, each solving a different question. Confusion between them is why people publish all three, still land in spam, and then add more records.
- SPF — is this connecting IP allowed to send as this address?
- DKIM — did the message leave our server unchanged, signed by a key we control?
- DMARC — what should receivers do when the two above disagree, and who gets told?
SPF
apur.in. TXT "v=spf1 ip4:203.0.113.10 include:_spf.example.net -all"
- Enumerate senders explicitly. Every
include:,a:,mx:andredirect=costs a DNS lookup, and the receiver is allowed to give up after ten. A record that exceeds the limit is a permanent SPF failure, not a soft one. - Use
-allonly once you are certain nothing else sends for the domain. Until then~all. The difference matters most to forwarders. - One SPF record per name — two TXT records starting with
v=spf1is a permanent error. This is the most common real-world SPF mistake. - SPF passes or fails on the envelope sender, which is usually not the address in the From header. That mismatch is exactly what DMARC alignment later judges.
DKIM
sel2026._domainkey.apur.in. TXT "v=DKIM1; k=rsa; t=s; p=MIGfMA0GCSq...long..."
- 2048-bit keys. 1024-bit DKIM keys are still accepted by verifiers and are weak; some receivers quietly discount them.
t=smeans strict: subdomains may not sign with the parent's domain key. Set it unless you actually need subdomain signing.- Do not publish
l=(body length). Verifiers ignore it, and its presence historically made partial-message forgeries cheaper. - Rotation is by selector, not by replacing a key in place: publish the new selector, switch signing over, keep the old selector published until in-flight mail has drained, then remove it. Replacing a key at the same selector name causes failures for as long as old signatures are being verified.
DMARC
_dmarc.apur.in. TXT "v=DMARC1; p=none; rua=mailto:dmarc@apur.in; pct=100; adkim=r; aspf=r"
Publish p=none first and read the aggregate reports for a few weeks. The
reports answer a question you cannot answer by thinking: who else is sending as this
domain — mailing lists, a scan-to-email printer, an old cron job, a forgotten relay.
Each source is a row with the connecting IP and whether SPF and DKIM passed and aligned.
Then move in steps, and only as far as the reports justify:
p=none → p=quarantine → p=reject. Jumping straight to
reject is how people discover that the printer had been sending all the
password resets.
- Alignment is the part DMARC adds. A message can pass both SPF and
DKIM and still fail DMARC if the authenticated domain does not match the From header.
aspf=s/adkim=srequire exact match rather than same-organisational-domain. sp=sets the policy for subdomains separately; a subdomain used by a marketing tool should not inheritrejectby accident.- Forwarding and mailing lists break SPF, and list software that edits the body breaks
DKIM. That is expected and is what
p=quarantineplus ARC-aware lists handle; it is not a reason to skip DMARC.
Two things people forget
Reverse DNS. The connecting IP must resolve to a hostname that resolves back to that IP, and the HELO name should match it. No authentication record rescues a server with no PTR; a surprising number of filters stop right there.
MTA-STS and TLS-RPT. If the domain receives mail, these two are worth
publishing: a _mta-sts TXT record with a version stamp, a policy file served
over HTTPS at /.well-known/mta-sts.txt starting at
mode=testing, and a _smtp._tls TXT record so that TLS failures
report themselves to you rather than silently downgrading.
Verifying
dig +short TXT apur.in
dig +short TXT sel2026._domainkey.apur.in
dig +short TXT _dmarc.apur.in
postscreen -d / postfix -t # what the local MTA believes it will send
Then send one real message to a mailbox you control on a strict provider and read the Authentication-Results header in the received message. It states SPF, DKIM and DMARC results in one line, and it is the only evidence that counts.