What it means
SMTP was designed in an era when every server on the network was trusted, so it has no notion of who a message really came from. Any host can open a connection and claim to be sending on behalf of any domain. DKIM, standardised in RFC 6376, is the patch. Before the message leaves, the sending system computes a cryptographic hash of the body and of a chosen set of headers, signs that hash with a private key, and writes the result into a new header called DKIM-Signature. The matching public key lives in a DNS TXT record. Any receiver in the world can therefore fetch the key and verify the signature without ever contacting the sender.
The important consequence is that DKIM survives forwarding. SPF checks the connecting IP address, so the moment a message is relayed through a mailing list or a university forwarding address the IP changes and SPF fails. A DKIM signature travels inside the message, so it keeps verifying no matter how many hops the message takes, provided nothing along the way edits what was signed. That is why DKIM, not SPF, is the authentication result you should treat as load bearing.
Anatomy of a DKIM-Signature header
Every tag in the header does something specific, and reading them in order is how you debug a failure without guessing. The tags you will actually see:
v=1: the DKIM version. Always 1; there has never been a second one.a=rsa-sha256: signing algorithm. RSA with SHA-256 is the default.ed25519-sha256is defined in RFC 8463 and produces a far shorter key, but is not universally verified yet.d=pinlyx.com: the signing domain identifier, or SDID. This is the domain that takes responsibility, and the one DMARC compares against yourFromheader.s=resend: the selector. It picks which key under the domain to use, which is what lets one domain run several signing systems at once.c=relaxed/relaxed: canonicalization for headers and body. See the section below; this one tag causes most real-world failures.h=from:to:subject:date:message-id: the ordered list of headers covered by the signature.Fromis mandatory. Anything not listed here can be changed or added in transit without breaking the signature.bh=: the base64 hash of the canonicalized body. When a verifier reports that the body hash did not verify, this is the value that no longer matches.b=: the signature itself, computed over the canonicalized headers listed inh=plus the DKIM-Signature header with an emptyb=.t=andx=: signature timestamp and expiry, as Unix seconds. An expired signature is treated as no signature at all.i=: the agent or user identifier, normally the signing domain or a subdomain of it. Rarely needed.l=: body length count. Do not use it, for the reason in the FAQ below.
The DNS side: what a selector record contains
The public key is published at selector._domainkey.yourdomain.com as a TXT record. Its own tag set is short:
v=DKIM1: version. If present it must come first.k=rsa: key type.rsais the default,ed25519the other legal value.h=sha256: which hash algorithms this key may be used with. Omitting it means any of them.p=: the base64 public key. An emptyp=is not a broken record, it is a revocation, and verifiers treat it as one.t=y: testing mode. Receivers are asked not to act on failures. Useful for a week, dangerous forever, because some receivers also refuse to let a testing key satisfy DMARC.t=s: thei=domain must exactly equald=, with no subdomains allowed.s=email: service type. Almost always left at its default of*.
Canonicalization, and why relaxed/relaxed is the answer
Mail servers along the path legitimately reshuffle whitespace. They re-fold long headers, they add or strip a trailing blank line, they change the case of a header name. Under simple canonicalization any of those edits changes the hash and the signature fails. Under relaxed, signer and verifier both normalise first: header names are lower-cased, runs of whitespace collapse to a single space, leading and trailing whitespace is trimmed, and trailing empty lines in the body are removed.
Sign with c=relaxed/relaxed unless you have a specific reason not to. It is what every major provider uses, and it removes an entire category of failure that is impossible to reproduce locally because it only happens on the hop you cannot see.
Reading a verification result
Receivers record what they found in an Authentication-Results header, defined in RFC 8601. It is the single most useful thing in a raw message when you are debugging, and because it is added by the receiving server it can be trusted in a way the rest of the headers cannot. It names the checking host first, then gives one result per method. If you see dkim=pass next to dmarc=fail, the signature was valid but the domain that signed it was not yours.
What DKIM does not do
- It is not encryption. The message is as readable in transit as it was before. TLS is what solves that.
- It is not a spam verdict. Spammers sign their mail correctly, and are often better at it than legitimate senders. A valid signature only makes reputation attributable.
- It does not protect the visible From line on its own. A signature with
d=some-vendor.neton a message readingFrom: you@yourdomain.comverifies perfectly and proves nothing about you. Alignment is a DMARC concept, not a DKIM one. - It does not cover headers you left out of
h=. IfList-Unsubscribeis not signed, a relay can replace it. Sign the headers that matter, including List-Unsubscribe andContent-Type.
Related concepts
- SPF: the IP-based half of the same problem, and the one that breaks on forwarding.
- DMARC: the policy layer that turns a DKIM pass into a decision about the From header.
- Domain warm-up: none of this matters until the receiving side has a reputation to attach your signature to.
- Bounce rate: where authentication failures show up first, as 5.7.x rejections.
- Cold outreach: the workflow where an unsigned sending path costs you the most.
How Pinlyx handles it
Outbound notifications, lifecycle mail and campaign sends all leave through a signing relay, so every message carries a signature whose d= is your own domain rather than ours. When you connect a sending domain we generate the selector, show the exact TXT record to paste, and then re-query it from outside your network before we let you send, because a record that resolves on your laptop and not on a public resolver is the most common setup failure we see. Inbound mail synced into the CRM keeps its original Authentication-Results header, so when a customer claims they never received a reply you can read what their provider actually decided.