AhaSend
Back to Blog

A Technical Deep Dive into SPF, DKIM, and DMARC for Developers

Mark Kraakman
Mark Kraakman
Insights

Most developers meet SPF, DKIM, and DMARC the same way: a deliverability problem lands on your desk, you search for the fix, and you paste three DNS records from a help article into your zone file. The emails start arriving. You move on. The records become magic incantations, present, working, and completely opaque.

That works right up until it doesn't. A forwarded email fails authentication for reasons that look insane. A subdomain starts getting rejected. Gmail begins quarantining your password resets the week after you added a new marketing tool to the same domain. Now you need to actually debug it, and "I pasted the records the article told me to" is not a mental model you can debug from.

This article builds the model. By the end you should be able to look at a raw DMARC record and a failed authentication header and reason about why it failed, not just which Stack Overflow answer to try next.

TL;DR: SPF authorizes which servers may send for your domain. DKIM cryptographically signs the message so tampering and forgery are detectable. DMARC ties the first two to the domain your recipients actually see in the From: field, that link is called alignment, and it's the part everyone forgets. You need all three, correctly aligned, to pass the bulk-sender rules Gmail, Yahoo, and Microsoft now enforce. The rest of this article is the mental model behind those records, so you can debug them instead of just pasting them.

The problem all three protocols are solving

SMTP, the protocol that moves essentially all email, was finalized in 1982 and assumed everyone on the network was trustworthy. It has no built-in concept of identity. Nothing in the base protocol stops a server from claiming to send mail as [email protected], the From: address is just a header the sender writes, like the return address on an envelope. You can write whatever you like.

That single design gap is why phishing works, and SPF, DKIM, and DMARC are three layered answers to one question: can the receiving server trust that this message really came from the domain it claims to be from? Each protocol answers a different slice of that question, which is exactly why you need all three rather than picking a favorite.

A useful frame before we go deep: SPF checks the envelope, DKIM checks the contents, and DMARC checks that either of those actually lines up with the name the human reads. Hold onto that as we take each in turn.

SPF: which servers are allowed to speak for you

Sender Policy Framework is the simplest of the three. You publish a TXT record listing the servers permitted to send mail for your domain. A receiving server looks up that record and checks whether the connecting server is on the list.

Here's what AhaSend has you publish:

Name: @ (or your subdomain)
Type: TXT
Value: v=spf1 include:spf.ahasend.com ~all

Read it left to right. v=spf1 declares the version. include:spf.ahasend.com means "also trust whatever spf.ahasend.com publishes", a delegation, so AhaSend can change its sending IPs without you ever touching your DNS again. ~all is the catch-all at the end: the ~ is a soft fail, telling receivers to accept mail from unlisted servers but mark it as suspicious. A -all would be a hard fail (reject outright), and +all would authorize the entire internet, which is a configuration error roughly equivalent to having no SPF at all.

Two things trip developers up constantly.

First, a domain may have only one SPF record. If you already have SPF for Google Workspace and you add a second TXT record for your email provider, you don't have two policies, you have an invalid configuration, and most receivers will fail it. You merge them into one record by adding the new include before the final mechanism:

OLD: v=spf1 include:_spf.google.com ~all
NEW: v=spf1 include:_spf.google.com include:spf.ahasend.com ~all

Second, and this is the subtle one that pays off when we reach DMARC, SPF authenticates the wrong address. It checks the envelope sender (also called the return-path or MAIL FROM), which is the address the sending servers negotiate at the SMTP layer. It is not the From: address your recipient sees in their client. Those two are usually different, and on most email platforms the envelope sender points at the provider's own domain for bounce handling. So a message can pass SPF for bounces.provider.com while displaying [email protected] to the human. SPF alone, therefore, proves almost nothing about the name in the From: field. Remember that, it's the whole reason DMARC exists.

DKIM: a signature that proves nothing was tampered with

DomainKeys Identified Mail closes a different gap. SPF says "this server is allowed to send." DKIM says "this specific message genuinely came from this domain and hasn't been altered in transit."

The mechanics are ordinary public-key cryptography. AhaSend holds a private key and, on the way out, signs each message, a canonicalized set of headers plus a hash of the body, producing a DKIM-Signature header. You publish the matching public key in DNS. The receiving server pulls your public key, recomputes the hash over the signed content, and verifies the signature. If the body or any signed header was modified after signing, the hash won't match and DKIM fails.

What you publish depends on whether your domain uses managed or manual DNS. AhaSend defaults new domains to managed DNS, which uses two CNAME records pointing back at AhaSend-hosted keys:

Name: managed._domainkey.(your domain)
Type: CNAME
Value: [AhaSend alias shown in your dashboard]

Name: managed2._domainkey.(your domain)
Type: CNAME
Value: [AhaSend alias shown in your dashboard]

That managed._domainkey prefix is the selector. Selectors let a single domain carry several DKIM keys at once, a message names its selector in the DKIM-Signature header, and the receiver knows exactly which public key to fetch. This is what makes key rotation safe: AhaSend can sign with a fresh key under a new selector while the old one is still valid, with zero downtime. That's why the managed setup hands you two selectors up front, one active, one standby for the next rotation. Publishing both now means a future rotation needs no DNS change from you at all. (AhaSend rotates DKIM keys automatically, that's a feature most providers make you do by hand, if at all.)

On a legacy or explicitly manual domain you'll instead see a single TXT record holding the public key directly:

Name: [selector]._domainkey.(your domain)
Type: TXT
Value: [the DKIM public key]

The crucial property of DKIM, and the reason it's the backbone of modern authentication: the signature survives forwarding. SPF breaks the moment a message is relayed through a mailing list or a forwarding rule, because the forwarding server isn't on your SPF list. The DKIM signature travels with the message, so as long as the signed content is intact, it still verifies. Hold this thought too.

DMARC: tying it all back to the name the human sees

Now the payoff. We have two protocols that each authenticate something, but, crucially, something other than the visible From: address. SPF authenticates the envelope sender. DKIM authenticates whatever domain the signer put in the signature. Neither, on its own, says anything about the yourdomain.com your recipient actually reads. A phisher can pass SPF and DKIM for a domain they do control while spoofing yours in the From: line.

DMARC plugs exactly that hole with one concept: alignment. A message passes DMARC when it passes SPF or DKIM and the domain that passed matches the domain in the visible From: header. That match is the entire point. It's not enough to be authenticated; you have to be authenticated as the domain you're claiming to be.

Here's the AhaSend-recommended record:

Name: _dmarc
Type: TXT
Value: v=DMARC1; p=quarantine; sp=none; adkim=r; aspf=r;

Tag by tag:

  • v=DMARC1, the version, required first.
  • p=quarantine, the policy for mail that fails alignment: send it to spam. The three options are none (monitor only, deliver as normal), quarantine (treat as suspicious), and reject (refuse at the SMTP layer). More on choosing below.
  • sp=none, the policy for subdomains, here set to monitor-only. Useful when your subdomains aren't all sending authenticated mail yet and you don't want to break them while you sort it out.
  • adkim=r and aspf=r, relaxed alignment for DKIM and SPF. Relaxed means the authenticated domain only has to share an organizational domain with the From: address, mail.yourdomain.com aligns with yourdomain.com. The alternative, s (strict), demands an exact match. Relaxed is the right default for almost everyone; strict breaks the moment you send from a subdomain.

Remember the two facts we flagged earlier? This is where they cash out. SPF authenticates the envelope sender, which usually belongs to your provider, so on most setups, SPF won't align with your From: domain, and DMARC leans on DKIM to carry the pass. And because DKIM survives forwarding, DKIM alignment is also what keeps your mail authenticated when it gets relayed through a mailing list. DKIM is doing the heavy lifting; SPF is the backup. That's not a quirk of AhaSend, it's true across the industry, and it's why "just set up SPF" was never enough.

Choosing your policy: none → quarantine → reject

DMARC is the one record you should roll out in stages rather than setting to its strictest value on day one.

Start at p=none. It changes nothing about delivery, it's pure monitoring. Because every DMARC record can request aggregate reports (add a rua=mailto:... tag pointing at an inbox or a DMARC analytics service), none lets you watch which sources are sending as your domain and whether they pass alignment, before you start blocking anything. You will almost always discover a legitimate sender you forgot about: a CRM, a helpdesk, an invoicing tool.

Once your reports show every legitimate source aligning cleanly, move to p=quarantine (failures go to spam) and finally p=reject (failures are refused outright). reject is the goal, it's the only policy that actually stops a spoofed email from reaching the inbox, but earning your way there with monitoring data means you reach it without blackholing your own payroll notifications.

Why this is no longer optional

Email authentication used to be a deliverability optimization. As of 2024 it's an entry requirement, and the rules are written in exactly the alignment terms you just learned. Google and Yahoo rolled out shared bulk-sender rules that took effect in February 2024, and Microsoft joined them in May 2025. If you send more than 5,000 messages a day to their users, the gateway now checks that you authenticate with both SPF and DKIM, publish a DMARC record (p=none is the floor that satisfies the rule, not the goal), and keep that DMARC aligned with your From: domain, plus offer one-click unsubscribe and keep your spam-complaint rate below 0.3%.

That middle requirement is the whole article in one line: the providers don't just want authentication, they want aligned authentication, because alignment is the only version that a phisher can't fake. Miss it and bulk mail gets throttled or rejected at the gateway, no spam folder, no second chance. And while the hard thresholds apply to bulk senders, the same signals feed the reputation scoring that decides where your transactional mail lands too. A verification email is worthless if it arrives after the user has given up, and these are the records that decide whether it arrives at all.

Debugging when something fails

Here's the model in action. When a message gets flagged, open the raw headers and find the Authentication-Results line your receiver added:

Authentication-Results: mx.google.com;
  dkim=pass header.d=yourdomain.com;
  spf=pass smtp.mailfrom=bounces.provider.com;
  dmarc=pass (p=QUARANTINE) header.from=yourdomain.com

Now you can read it. dkim=pass header.d=yourdomain.com, DKIM verified and the signing domain is yours, so this will align. spf=pass smtp.mailfrom=bounces.provider.com, SPF passed, but for the provider's bounce domain, not your From: domain, so SPF does not align here. dmarc=pass ... header.from=yourdomain.com, DMARC passed anyway, because it only needs one aligned mechanism and DKIM delivered it. This is the normal, healthy state for most setups, and now you know why instead of just hoping.

When DMARC fails, it's almost always one of three things: DKIM isn't signing with your domain (so there's nothing aligned to fall back on), you set adkim=s/aspf=s and a subdomain mismatch is tripping strict alignment, or a legitimate third-party tool is sending as your domain without being authenticated at all, exactly the discovery p=none reporting is designed to surface.

One whole class of these bugs simply can't happen on AhaSend. You cannot send through a domain whose DNS isn't correctly configured, because AhaSend verifies SPF, DKIM, and DMARC continuously rather than once at setup. A record that drifts or a key that stops resolving fails fast and visibly at send time, instead of quietly degrading your inbox placement for a week before anyone notices. The full record-by-record walkthrough, including the optional return-path, tracking, and MX records, lives in the domain setup guide.

The model, in one paragraph

SPF lists the servers allowed to send for your domain, but authenticates the envelope, not the visible sender. DKIM signs the message itself so tampering is detectable and authentication survives forwarding. DMARC is the keystone: it requires that SPF or DKIM not only pass but align with the From: address your recipient actually reads, and it lets you ramp from monitoring to outright rejection as your reporting data earns the confidence. Get all three aligned and you've done more for your deliverability, and your users' trust, than any subject-line tweak ever will.

Start for free on AhaSend →

A Technical Deep Dive into SPF, DKIM, and DMARC for Developers | AhaSend