DMARC Engine
Home/Knowledge base/How do I set up DKIM for my domain?
Knowledge base

How do I set up DKIM for my domain?

DKIM is the part of email authentication that proves a message genuinely came from your domain and was not altered on the way.

21 June 2026 · 16 min read

DKIM is the part of email authentication that proves a message genuinely came from your domain and was not altered on the way. Where SPF authorises sending IP addresses, DKIM does something quite different: it attaches a cryptographic signature to each message, computed with a private key that only your sending system holds, and publishes the matching public key in your DNS. A receiving server fetches that public key, recomputes the signature over the headers and body it received, and either confirms the maths checks out or it does not. Setting DKIM up correctly is one of the three things that lets you eventually move a domain to p=reject without losing mail, and unlike SPF it survives most forwarding intact, which makes it the more durable of the two authentication mechanisms underneath DMARC.

This guide walks the whole job end to end: how DKIM works at a level that helps you debug it, how keys and selectors fit together, where the public key record actually lives in DNS, how to enable signing at the common providers, and how to verify that signing is not just happening but is aligned with your domain in a way DMARC will accept. The last point is where most setups quietly fail, so it gets the attention it deserves. If you would rather not touch any of this by hand, DMARC Engine generates and hosts the keys for you and rotates them on a schedule, which we cover at the end, but the manual path below is worth understanding either way.

What DKIM actually does, in one pass

A DKIM signature is a header your mail server adds called DKIM-Signature. It is the visible output of a process that runs on every outgoing message:

  1. The sending system selects a set of headers (always including From) and the message body.
  2. It computes a hash of the body and a hash of those headers.
  3. It encrypts a value derived from those hashes with a private key to produce the signature.
  4. It stamps the message with a DKIM-Signature header that records which domain signed (d=), which key to use (s=, the selector), which headers were covered (h=), and the signature itself (b=).

On the receiving end, the server reads the d= and s= values, looks up a TXT record in DNS at a predictable location built from those two values, and pulls out the public key. Because the public and private keys are a matched pair, the receiver can verify the signature without ever holding your secret. If anyone altered a signed header or the body in transit, the recomputed hash will not match and DKIM fails. If the message arrived intact and the key matches, DKIM passes.

That is the whole mechanism. Two ideas do all the work: a keypair where the private half signs and the public half verifies, and a selector that lets you publish more than one key at a time. Everything else is plumbing. The protocol itself is summarised at /glossary/dkim, and the selector concept, which trips up a lot of people, has its own entry at /glossary/dkim-selector.

Why DKIM matters more than it looks

On its own a passing DKIM signature does very little. A message can be perfectly DKIM-signed by mailchimp.com and still be spoofing your brand in the visible From address, and a receiver acting on DKIM alone would shrug. DKIM becomes powerful only when DMARC layers alignment on top of it: DMARC requires that the domain in the DKIM d= tag matches (or is a relaxed-subdomain match of) the domain in the visible From header. A signature from mailchimp.com does not align with a From of you@yourdomain.com; a signature with d=yourdomain.com does. This is the single most important fact in this whole guide, and we return to it in the verification section. For the underlying rule, see /glossary/dmarc-alignment.

Before you start: inventory your senders

DKIM is configured per sending source, not once for the whole domain. Every system that sends mail as your domain needs its own DKIM setup, with its own selector and its own key. A typical organisation has more of these than it expects:

  • The primary mailbox provider, for example Google Workspace or Microsoft 365.
  • Marketing platforms such as Mailchimp, Brevo or Klaviyo.
  • Transactional senders such as Amazon SES, SendGrid, Postmark or Mailgun.
  • Helpdesk, CRM, invoicing, recruitment and survey tools that send on your behalf.

If you skip one, that source will fail DKIM, and when you eventually enforce DMARC, its mail can be quarantined or rejected. The honest first step is therefore not generating a key but finding everything that sends mail. The fastest way to build that list is to publish a DMARC record at monitoring level (p=none with an rua address) and read a couple of weeks of aggregate reports, which name every IP and domain sending as you. We cover that flow in /kb/check-dmarc-is-working, and you can paste reports straight into the /tools/dmarc-report-analyzer to see which sources are already signing and which are not.

Step 1: Generate a DKIM keypair (or let the provider do it)

There are two ways a key comes into existence, and which one you use depends on the sender.

Provider-managed keys. Most large platforms generate the keypair for you. You never see the private key; it lives inside their infrastructure. They show you the public-key DNS record (or just a hostname to CNAME to), and your only job is to publish it. Google Workspace, Microsoft 365, Mailchimp, SendGrid and SES all work this way. This is the common case and the easier one, because you cannot mishandle a private key you never touch.

Self-generated keys. Some self-hosted mail servers (Postfix with OpenDKIM, for instance) need you to create the keypair yourself. The standard tool is OpenSSL. Generate a 2048-bit RSA private key and extract its public half:

openssl genrsa -out yourdomain.private 2048
openssl rsa -in yourdomain.private -pubout -out yourdomain.public

Use 2048-bit RSA as the default. 1024-bit keys still verify but are now considered weak and some receivers discount them; 4096-bit keys are stronger but produce a public key that can exceed the 255-character limit of a single DNS string and must be split into multiple quoted chunks, which causes publishing mistakes. 2048 is the sweet spot that every receiver accepts and that fits cleanly into DNS. If you prefer not to run OpenSSL, the /tools/dkim-generator produces a correctly formatted keypair and the exact DNS record to publish.

Keep the private key secret and backed up. Anyone who obtains it can sign mail as your domain, and losing it means re-keying the source from scratch. It should live only on the sending system, with file permissions that prevent other users reading it.

Step 2: Choose a selector

A selector is a short label that names one specific key. It is the reason a domain can run several DKIM keys at once without them colliding: each key gets its own selector, and the DKIM-Signature header on each message points at the selector that signed it. The receiver combines the selector with your domain to find the right public key.

Selectors are arbitrary strings that you (or your provider) choose. You will see conventions like:

  • google or google._domainkey for Google Workspace.
  • selector1 and selector2 for Microsoft 365 (it ships two, for rotation).
  • s1, k1, mail, dkim, or a date-stamped value like 2026a.

When you control the selector, a date or version style such as 2026a is sensible because it makes rotation obvious: the next key becomes 2026b and you can run both in parallel during a changeover. The one rule is that a selector must be unique among the keys on your domain. Two different keys cannot share a selector. More on the selector model at /glossary/dkim-selector.

Step 3: Publish the public key in DNS

This is the step that fails most often, almost always because the record is published at the wrong hostname. The DKIM public key lives at a hostname built from the selector and a fixed label:

<selector>._domainkey.yourdomain.com

So a key with selector 2026a on yourdomain.com is published at 2026a._domainkey.yourdomain.com. The _domainkey label is mandatory and literal; it is not a placeholder. Miss it, or put the key at the apex, and no receiver will ever find it.

The record type is usually TXT. Its value looks like this (wrapped here for readability; in DNS it is one logical string):

v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...your-long-public-key...AQAB

The tags inside it:

  • v=DKIM1 declares the record version. It must come first.
  • k=rsa is the key type. RSA is the universal default; some setups use Ed25519, in which case k=ed25519.
  • p= is the public key itself, a long base64 string. This is the part that must be copied exactly, with no inserted spaces or line breaks.

A few publishing realities to get right:

  • Long values and the 255-character limit. A single DNS TXT string maxes out at 255 characters, and a 2048-bit public key is longer than that. Most DNS providers handle the split for you automatically when you paste the whole value into one TXT record; some require you to split it yourself into adjacent quoted strings inside the same record. Either way the receiver reassembles them. The failure mode is splitting it into two separate records, which is invalid. The /glossary/dkim entry has more on this if you hit a wall.
  • Provider CNAME records. Many platforms do not ask you to publish a TXT record at all. Instead they give you one or more CNAME records pointing your selector hostname at a hostname they control, so they can manage and rotate the underlying key without you ever touching DNS again. Google and most modern ESPs work this way. Publish the CNAME exactly as given; do not "helpfully" convert it to a TXT record.
  • No quotes, no trailing dots, no surprises. Paste the value as provided. Adding stray quotation marks or whitespace inside the p= value is a classic reason a record exists but does not verify.

After publishing, confirm the record resolves before you move on. From a terminal:

dig +short TXT 2026a._domainkey.yourdomain.com

On Windows:

nslookup -type=TXT 2026a._domainkey.yourdomain.com

DNS changes are not instant; depending on the TTL on the record they can take minutes to a few hours to be visible everywhere. If dig returns nothing, wait, then check across multiple public resolvers with the /tools/dns-propagation-checker rather than trusting one possibly-cached answer.

Step 4: Enable signing at your sending provider

Publishing the key does nothing until your sending system actually starts adding DKIM-Signature headers. This is a separate switch, and forgetting it is the second most common DKIM mistake after wrong hostnames. The exact steps vary by provider; here is the shape of it for the common ones.

Google Workspace

In the Admin console, go to Apps, Google Workspace, Gmail, Authenticate email. Generate a DKIM key for your domain (choose 2048-bit), which yields a google._domainkey TXT record. Publish that record in your DNS. Return to the console and click Start authentication. That final click is what enables signing; the key alone does nothing. Google signs with the google selector and d=yourdomain.com, which aligns cleanly.

Microsoft 365

In the Microsoft 365 Defender portal, under Email & collaboration, Policies & rules, Threat policies, Email authentication settings, DKIM, select your domain. Microsoft shows two CNAME records (selector1._domainkey and selector2._domainkey) pointing into onmicrosoft.com. Publish both, then toggle Enable for the domain. Two selectors exist so Microsoft can rotate keys without an outage.

Amazon SES

In the SES console, under Verified identities, select your domain and open the DKIM section. SES offers Easy DKIM, which generates three CNAME records. Publish all three. SES begins signing automatically once it detects the records, with d= set to your domain. Confirm the identity reaches "Successful" DKIM status in the console.

SendGrid, Mailgun, Postmark, Brevo and similar ESPs

These follow the same pattern: in the sender authentication or domain settings area, add your domain, and the platform returns a set of CNAME records (typically a couple of DKIM selectors plus a return-path/SPF record). Publish them all, then click verify. The platform signs every message it sends for you once verification passes. The detail differs but the idea does not.

Because the steps drift as these dashboards change, treat the above as orientation and follow the provider's current screens for the exact labels.

Step 5: Verify the signature exists and validates

Now confirm two distinct things: that messages are being signed at all, and that the signature actually verifies against your published key.

The quickest manual check is to send yourself a message and inspect the raw headers. In Gmail, open the message, use the three-dot menu and choose Show original. Gmail prints an authentication summary near the top:

DKIM:       'PASS' with domain yourdomain.com

PASS with domain yourdomain.com is exactly what you want. PASS with some other domain (an ESP's domain) means the message is signed but not by you, which matters for alignment, covered next. FAIL means the signature did not verify; usual causes are a wrong or not-yet-propagated DNS record, signing not actually enabled, or a key mismatch.

For a non-Gmail or more thorough check, paste your domain and selector into the /tools/dkim-checker. It fetches the public key at <selector>._domainkey.yourdomain.com, confirms the record parses, checks the key length, and flags common faults such as a missing v=DKIM1, an empty p=, or a split-into-two-records error. Use it once per selector so every active key is accounted for.

Step 6: Confirm DKIM alignment, the step that actually matters for DMARC

This is the part people skip and then wonder why DMARC still fails. A passing DKIM signature is necessary but not sufficient. DMARC asks a further question: does the domain that signed match the domain in the visible From address?

Concretely, DMARC compares the d= value in the DKIM-Signature header against the domain in the From header that recipients see.

  • If you send From: you@yourdomain.com and the signature carries d=yourdomain.com, the message is aligned and DMARC counts the DKIM pass.
  • If the same message is signed only with d=someses.amazonses.com or d=sendgrid.net, the signature passes on its own terms but does not align, so DMARC does not credit it.

Relaxed alignment (the default) accepts a subdomain match, so a signature with d=mail.yourdomain.com aligns with a From of you@yourdomain.com. Strict alignment demands an exact match. Almost everyone uses relaxed, and the difference is explained at /glossary/dmarc-alignment.

The practical lesson: when you configure DKIM at an ESP, make sure you are signing with your domain, not the platform's shared signing domain. This is why every provider asks you to add a domain and publish CNAME records; doing so is what lets them sign as d=yourdomain.com instead of their own domain. If you only verified an email address rather than a domain, or you skipped the DNS records, the ESP will still send your mail but sign it with its own d=, and DMARC will not align.

To check alignment across all your real traffic rather than one test message, read your DMARC aggregate reports. They report, per source, whether DKIM passed and whether it aligned. A source showing DKIM pass but DKIM-aligned fail is the exact signature of the "signed by the ESP, not by you" problem. Walk through reading these in /kb/read-a-dmarc-aggregate-report, or drop a report into the /tools/dmarc-report-analyzer to see alignment broken down by sender.

DKIM, SPF and DMARC together

DKIM is one leg of a three-legged setup. DMARC passes if either SPF or DKIM passes with alignment, so they provide redundancy rather than duplication. The two behave differently in the wild:

  • SPF authenticates the sending IP and the Return-Path (envelope) domain. It breaks on forwarding, because the forwarder becomes the new sending IP. SPF setup and the dreaded ten-lookup limit are covered in /kb/fix-a-failing-spf-record and the /tools/spf-checker.
  • DKIM authenticates the message content via a signature, independent of the IP. It survives plain forwarding because the signed headers and body usually travel unchanged. It breaks only when something rewrites a signed header or alters the body, which is why mailing lists can defeat it (they often modify subjects and append footers).

Because of this, DKIM is the more resilient of the two, and for any domain that gets forwarded or sent through intermediaries, having DKIM aligned is what keeps DMARC passing when SPF does not. For why forwarding causes this, see /kb/why-forwarding-breaks-authentication. The bigger picture of how the records interlock is in /kb/email-authentication-overview, and the policy layer that ties it all together is at /products/dmarc and the /tools/dmarc-checker.

Key rotation: the maintenance you should not skip

A DKIM key is not a set-and-forget artefact. Keys should be rotated periodically (quarterly to twice a year is a common cadence) so that a key compromised at some point in the past cannot be used to sign mail indefinitely. Rotation is also non-negotiable if a private key is ever exposed.

Rotation is exactly why selectors exist. The zero-downtime procedure is:

  1. Generate a new keypair with a new selector, for example 2026b.
  2. Publish the new public key at 2026b._domainkey.yourdomain.com and confirm it resolves.
  3. Switch the sending system to sign with the new selector.
  4. Verify that fresh mail now passes DKIM with the new selector.
  5. Leave the old selector published for a grace period (a week or two) so that in-flight and recently-sent mail still verifies.
  6. Remove the old key once nothing is signing with it.

Running both keys in parallel during the changeover is the whole point; it means no message is ever signed with a key whose public record is missing. The mechanics are detailed at /glossary/dkim-key-rotation. Many provider-managed setups (Microsoft 365 with its two selectors, for instance) rotate for you, which is one fewer thing to track.

Common DKIM failures and how to read them

A short field guide to the errors you will actually meet:

  • No DKIM-Signature header at all. Signing is not enabled at the provider. Publishing the key is not enough; you must flip the signing switch (Google's "Start authentication", Microsoft's "Enable", and so on).
  • DKIM fails to verify. The public key in DNS does not match the signing key, or has not propagated, or was published at the wrong hostname (missing _domainkey), or the p= value got mangled with stray whitespace. Re-check with the /tools/dkim-checker.
  • DKIM passes but DMARC still fails. Almost always an alignment problem: the message is signed with the ESP's d=, not yours. Verify the domain at the ESP and publish its DNS records so it signs as your domain.
  • Worked, then broke after a rotation. The old selector was removed before all mail signed with it had cleared, or the new selector's record was never published. Keep both live during a changeover.
  • Body hash mismatch on forwarded or list mail. Something altered the signed body in transit. This is expected for mailing lists; it is one reason DMARC accepts an aligned SPF pass as an alternative, and why ARC exists for trusted forwarders.
  • l= tag surprises. If a signature uses the l= (body length) tag, only part of the body is signed and content can be appended without breaking the signature, which is a minor security weakness. Most modern signers omit l=; if yours sets it, consider turning it off.

The done-for-you path

Everything above is doable by hand, and for a single Google Workspace domain it is genuinely a fifteen-minute job. The work compounds, though, once you have several sending sources, multiple domains, and a rotation schedule to honour. Each source needs its own selector, its own published record, signing enabled, alignment confirmed, and a rotation that runs without dropping mail.

DMARC Engine handles this lifecycle for you. It generates the keys, hosts the _domainkey records, enables and verifies signing across your sources, watches alignment in your aggregate reports, and rotates keys on a schedule with the old selector kept live through the grace window so nothing breaks. The DKIM piece is described at /products/dkim, and it sits inside the wider job of taking a domain from p=none to p=reject safely, which is the whole platform: SPF flattening at /products/spf, policy management at /products/dmarc, plus /products/mta-sts and /products/bimi once authentication is solid. If you want to know what enforcement requires in full, the /requirements page lays out the checklist.

Quick checklist

To set up DKIM for a domain, in order:

  1. Inventory every system that sends mail as your domain.
  2. For each source, generate a 2048-bit keypair or accept the provider-managed key.
  3. Choose a unique selector per key.
  4. Publish the public key (TXT or provider CNAME) at <selector>._domainkey.yourdomain.com.
  5. Confirm the record resolves with dig or the /tools/dns-propagation-checker.
  6. Enable signing at the provider; do not stop at publishing the key.
  7. Send a test message and confirm DKIM: PASS with domain yourdomain.com.
  8. Validate each key with the /tools/dkim-checker.
  9. Confirm alignment (d= matches your From domain) in aggregate reports.
  10. Set a rotation cadence and keep the old selector live during changeovers.

Get those ten right for every sender and DKIM will be the dependable, forwarding-resistant leg of your DMARC setup, the one that keeps your legitimate mail passing all the way up to p=reject.

Share

See where your domain stands today

Run a free DMARC scan, then let us take you to enforced p=reject with no email outage.