SPF, DKIM, and DMARC: Email Security for Web Developers
If you've ever set up a custom domain for your web app, you've probably seen SPF, DKIM, and DMARC mentioned in your email provider's setup guide. Most developers add the DNS records, tick the box, and move on without fully understanding what they do.
Here's the problem: if these records are missing or misconfigured, anyone can send emails that appear to come from your domain. That means phishing emails that look like they're from your app, password reset notifications from "you" that lead to credential harvesting, and transactional emails that land in spam instead of inboxes.
These three records work together. Here's what each one does and how to set them up properly.
SPF: who can send on your behalf
SPF (Sender Policy Framework) is a DNS TXT record that lists which mail servers are allowed to send email from your domain. When a receiving mail server gets an email claiming to be from your domain, it checks your SPF record to see if the sending server is on the list.
A basic SPF record looks like this:
v=spf1 include:_spf.google.com include:amazonses.com -all
This says: Google's servers and Amazon SES can send email from my domain. Nobody else can (-all).
The key part is the -all at the end. This tells receiving servers to reject emails from any server not listed. There are three options:
-all (hard fail): reject unauthorised senders. This is what you want.
~all (soft fail): accept but mark as suspicious. This is weaker and still lets spoofed emails through, often to the spam folder.
?all (neutral): no opinion. This effectively disables SPF. Don't use this.
Common mistake: using ~all instead of -all. Many setup guides recommend soft fail "to avoid delivery issues." In practice, hard fail is safe if you've listed all your legitimate sending services. Start with soft fail if you're unsure, monitor for a week, then switch to hard fail.
How to set it up
Add a TXT record to your domain's DNS:
Type: TXT
Name: @
Value: v=spf1 include:_spf.google.com -all
If you use multiple email services (e.g., Google Workspace for team email and Resend for transactional email), include all of them:
v=spf1 include:_spf.google.com include:resend.com -all
Important: you can only have one SPF record per domain. If you add multiple TXT records starting with v=spf1, SPF validation will fail. Combine all your senders into a single record.
DKIM: proving the email wasn't tampered with
DKIM (DomainKeys Identified Mail) adds a cryptographic signature to every email sent from your domain. The sending server signs the email with a private key, and the receiving server verifies the signature using a public key published in your DNS.
This proves two things: the email genuinely came from a server that has your private key, and the email content wasn't modified in transit.
A DKIM DNS record looks like this:
Type: TXT
Name: google._domainkey
Value: v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAO...
The Name field varies by provider. Google uses google._domainkey, Resend uses resend._domainkey, and so on. Each email service gives you the specific record to add.
How to set it up
Your email provider generates the DKIM key pair. You just need to add the public key as a DNS record. The process differs by provider:
Google Workspace: go to Admin, then Apps, then Gmail, then "Authenticate email." Google generates the record. Copy it to your DNS.
Resend: add and verify your domain in the Resend dashboard. They provide the DKIM records to add.
Amazon SES: use the "Easy DKIM" setup, which gives you three CNAME records to add.
Recommendation: use 2048-bit DKIM keys, not 1024-bit. Most providers default to 2048-bit now, but check. Longer keys are harder to forge.
DMARC: what to do when checks fail
DMARC (Domain-based Message Authentication, Reporting, and Conformance) tells receiving servers what to do when an email fails SPF and DKIM checks. It's the policy layer that sits on top of both.
A basic DMARC record:
Type: TXT
Name: _dmarc
Value: v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com; pct=100
The p= value is the policy:
p=none: monitor only. Failed emails are delivered normally, but you get reports. Use this when you're first setting up DMARC.
p=quarantine: failed emails go to spam. This is a good middle ground.
p=reject: failed emails are rejected entirely. This is the strongest protection and what you should aim for once you're confident your SPF and DKIM are correctly configured.
The rua= value is where aggregate reports are sent. These XML reports show you who's sending email from your domain, including legitimate senders you might have forgotten to add to your SPF record.
The recommended rollout
Don't jump straight to p=reject. Roll out DMARC in stages:
Week 1-2: p=none with reporting. Monitor the reports to see who's sending email from your domain. Make sure all legitimate senders are in your SPF record and have DKIM configured.
Week 3-4: p=quarantine with pct=50. This quarantines 50% of failing emails, letting you catch issues without blocking everything.
Week 5+: p=quarantine with pct=100, then eventually p=reject.
# Stage 1: Monitor
v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com; pct=100
# Stage 2: Quarantine
v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com; pct=100
# Stage 3: Reject
v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com; pct=100
How they work together
When someone receives an email from your domain, the receiving server does three checks in order:
SPF: is the sending server listed in your SPF record?
DKIM: does the email have a valid cryptographic signature?
DMARC: if either check failed, what should I do?
For an email to pass DMARC, it needs to pass either SPF or DKIM (not both). But best practice is to configure both so you have redundancy.
A complete setup
Here's what the complete DNS configuration looks like for a domain using Google Workspace and Resend:
# SPF - one record listing all senders
TXT @ v=spf1 include:_spf.google.com include:resend.com -all
# DKIM - one record per sender
TXT google._domainkey v=DKIM1; k=rsa; p=MIIBIjAN...
TXT resend._domainkey v=DKIM1; k=rsa; p=MIGfMA0G...
# DMARC - policy
TXT _dmarc v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com; pct=100
How to check yours
You can check your records manually using dig or nslookup:
dig TXT yourdomain.com # Check SPF
dig TXT _dmarc.yourdomain.com # Check DMARC
dig TXT google._domainkey.yourdomain.com # Check DKIM
For an automated check, run your domain through Hexora at hexora.uk. It checks all three records and flags missing or weak configurations with specific remediation guidance.
Stop someone else sending as you
SPF, DKIM, and DMARC together prevent domain spoofing, improve email deliverability, and protect your users from phishing attacks that impersonate your app. Setting all three up takes about 20 minutes. If you're running a web app with a custom domain and sending transactional emails, this is non-negotiable.
Worried about your own site's security? Get a free scan in seconds.
Scan your site for free