Fundamentals
T1566SPF and DKIM
How email authentication works — SPF, DKIM, and DMARC — why they matter for stopping spoofed mail, how to verify them from the command line, and what happens when they are missing or misconfigured.
View on Graph
What They Are and Why They Matter
SPF and DKIM are how email servers verify a message actually came from who it claims to. Without them, anyone can send mail that looks like it came from your domain. With them, receiving servers can authenticate the sender.
Most phishing campaigns exploit missing or weak SPF and DKIM — it is the difference between a spoofed domain landing in an inbox vs. getting rejected outright.
The Three Layers
| Layer | What It Does | Where It Lives |
|---|---|---|
| SPF | Lists which mail servers are authorized to send email for your domain. | DNS TXT record. |
| DKIM | Attaches a cryptographic signature to each email. Receiving servers verify the signature against a public key in your DNS. | DNS TXT record (public key) + email header (signature). |
| DMARC | Tells receiving servers what to do when SPF or DKIM fails — allow, quarantine, or reject. Provides reporting so you can see who is sending mail as your domain. | DNS TXT record. |
SPF — Sender Policy Framework
SPF is a DNS TXT record that lists which servers can send mail for your domain.
Anatomy of an SPF Record
v=spf1 include:_spf.google.com ~all
| Component | Meaning |
|---|---|
v=spf1 | Identifies this as an SPF record (version 1). |
include:_spf.google.com | Delegates to Google’s mail server list. The receiving server looks up _spf.google.com and checks its SPF record. |
ip4:203.0.113.0/24 | (Optional) Directly authorize a specific IP range to send mail. |
include:spf.protection.outlook.com | (Optional) Microsoft 365 mail servers. |
~all | Soft-fail — mark messages from unauthorized servers as suspicious but deliver them. |
-all | Hard-fail — reject messages from unauthorized servers. |
?all | Neutral — no policy statement. |
SPF Mechanisms (in order of evaluation)
| Mechanism | Example | Behavior |
|---|---|---|
all | -all | Matches any IP. Always the last mechanism. |
ip4 | ip4:192.0.2.0/24 | Matches an IPv4 address or range. |
ip6 | ip6:2001:db8::/32 | Matches an IPv6 address or range. |
a | a:mail.example.com | Matches the A/AAAA record of the domain. |
mx | mx | Matches the MX servers of the domain. |
include | include:_spf.google.com | Delegates to another domain’s SPF policy. |
exists | exists:%{i}._spf.example.com | Advanced — checks a dynamic domain. |
Common SPF Mistakes
| Mistake | Impact |
|---|---|
| Forgetting to add a new mail-sending service | All mail from the new service fails SPF and goes to spam or is rejected. |
| Exceeding the 10 DNS lookup limit | SPF has a maximum of 10 DNS lookups (each include, a, mx, exists counts). Exceeding it causes the entire SPF check to fail (permerror). |
Using +all (pass all) | Defeats the purpose entirely. Any server can send mail for your domain. |
Not using -all | Without a hard fail policy, receiving servers may not reject spoofed mail. |
| Missing SPF record entirely | Any server can send mail that appears to come from your domain. Receiving servers have no way to authenticate it. |
DKIM — DomainKeys Identified Mail
DKIM uses public-key cryptography to sign each outgoing email. The sender’s mail server generates a signature header using a private key. The receiving server looks up the corresponding public key in DNS (via a DKIM TXT record) and verifies the signature.
How DKIM Works
Sender (private key) ── signs ──> Email with DKIM-Signature header
│
▼
Receiver (public key) <── verifies <── DNS lookup of selector._domainkey.example.com
DKIM Header Example
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=example.com; s=google;
h=mime-version:from:date:message-id:subject:to;
bh=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=;
b=GwBkL5hKx7yQz3Xp...
| Field | Meaning |
|---|---|
v=1 | DKIM version |
a=rsa-sha256 | Signing algorithm |
c=relaxed/relaxed | Canonicalization (relaxed allows minor whitespace changes) |
d=example.com | The signing domain |
s=google | The selector — tells the receiver which DNS record to query |
h= | Header fields included in the signature |
bh= | Body hash (base64) |
b= | The actual cryptographic signature |
DKIM DNS Record Example
The receiving server queries: google._domainkey.example.com
google._domainkey.example.com. TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDD..."
| Field | Meaning |
|---|---|
v=DKIM1 | DKIM version |
k=rsa | Key type (RSA, or ed25519 for newer deployments) |
p= | Public key (base64-encoded) — this is the key the receiver uses to verify the signature |
DMARC — Domain-based Message Authentication, Reporting & Conformance
DMARC tells receiving servers what to do when SPF and/or DKIM fail. It also provides daily reports about who is sending email claiming to be from your domain.
DMARC Record Example
_dmarc.example.com. TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com; pct=100"
| Field | Meaning |
|---|---|
v=DMARC1 | DMARC version |
p=none | Monitor only — receive reports but take no action. Start here. |
p=quarantine | Mark failing mail as spam. |
p=reject | Reject failing mail entirely. The goal state for most orgs. |
pct=100 | Percentage of mail to apply the policy to (100 = all). |
rua=mailto:dmarc@example.com | Aggregated report destination email. |
ruf=mailto:dmarc-forensics@example.com | Forensic (per-message) report destination. |
sp=reject | Subdomain policy — applies the policy to subdomains too. |
adkim=r | DKIM alignment — r (relaxed) allows the DKIM domain to be a subdomain of the From domain. |
DMARC Progression Strategy
- Monitor — Set
p=none. Review reports for 30 days to see what mail is failing authentication. - Quarantine — Move to
p=quarantine. Identify legitimate senders that are failing and fix their SPF/DKIM configuration. - Reject — Set
p=reject. Only after confirming all legitimate mail passes authentication.
Verification — Command-Line Tools
Verify SPF with nslookup
# Check SPF record for a domain
nslookup -type=TXT example.com
# Expected output (in a working SPF setup):
# example.com text = "v=spf1 include:_spf.google.com ~all"
# Directly query for SPF (type 99)
nslookup -type=SPF example.com
Alternative with dig (more readable):
dig TXT example.com +short
# "v=spf1 include:_spf.google.com ~all"
Verify DKIM with nslookup
# DKIM records use the format: <selector>._domainkey.<domain>
nslookup -type=TXT google._domainkey.example.com
# Expected output:
# google._domainkey.example.com text = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDD..."
Verify DMARC with nslookup
nslookup -type=TXT _dmarc.example.com
# Expected output:
# _dmarc.example.com text = "v=DMARC1; p=reject; rua=mailto:dmarc@example.com; pct=100"
Online Verification Tools
| Tool | What It Does |
|---|---|
| MXToolbox SPF | Validates SPF record syntax and checks for common issues (10 lookup limit, include loops). |
| DKIM Validator | Sends a test email and shows if DKIM, SPF, DMARC pass. |
| DMARC Analyzer | Monitors DMARC reports and helps with the p=none → p=reject transition. |
| DMARC Checker | Quick DMARC record validation. |
Walkthrough — Verifying a Domain’s Email Security
Let’s walk through verifying wyzsec.com:
Step 1 — Check SPF:
$ dig TXT wyzsec.com +short
"v=spf1 include:_spf.google.com include:spf.protection.outlook.com -all"
✅ SPF authorizes Google Workspace and Microsoft 365 mail servers. The -all means mail from any other server is rejected.
Step 2 — Check DKIM:
$ dig TXT google._domainkey.wyzsec.com +short
"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8..."
✅ DKIM public key published. Selector google matches Google Workspace.
Step 3 — Check DMARC:
$ dig TXT _dmarc.wyzsec.com +short
"v=DMARC1; p=reject; rua=mailto:dmarc@wyzsec.com; pct=100"
✅ DMARC set to reject. Reports are sent to dmarc@wyzsec.com.
Step 4 — Send a test email and check headers:
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of user@wyzsec.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=user@wyzsec.com;
dkim=pass header.i=@wyzsec.com;
dmarc=pass (p=REJECT, sp=REJECT)
✅ All three pass.
Detection — Identifying Email Spoofing in Logs
Microsoft 365 Message Trace — Look for:
SPF: FailorDKIM: FailAuthentication-Resultsheader showsspf=softfailordkim=fail- DMARC disposition: delivered but DMARC
p=quarantineorp=rejectin thedmarc=failrow
Exchange Online — Get-MessageTrace to see:
SPFStatus: FailDKIMStatus: FailDMARCStatus: Fail
Suspicious patterns:
- Email from your CEO but SPF/DKIM both fail
- Lookalike domains (
wyzsec-support.com,wyzsec-verify.com) sending mail that passes their own SPF/DKIM — this is a lookalike domain phishing attack, which SPF/DKIM for your domain does NOT protect against (that requires DMARC reporting and domain monitoring) - Sudden increase in DMARC aggregate reports showing many unauthorized senders
Related
- Kill Chain — covers the kill chain concepts
- OSI Model — covers the osi model concepts
- Phishing — detection and response for T1566 techniques
- Business Email Compromise Response — detection and response for T1566, T1114, T1098, T1586 techniques
- Initial Access Response — detection and response for T1566, T1190, T1189, T1133 techniques
