# DKIM

DKIM attaches a cryptographic signature to a message. The sending domain publishes a public key in DNS under a **selector**; the sender signs chosen headers and the body with the private key; the receiver fetches the key and verifies. Unlike SPF the signature travels with the message, so it survives forwarding — until something rewrites what was signed.

- **Status:** Reference
- **Audience:** both, developer
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/technology/dkim/

## Anatomy of a signature

```text
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
  d=example.net; s=key2026; h=from:to:subject:date:message-id;
  bh=<body hash>; b=<signature>
```

**`d=`** — The signing domain. This is what DMARC alignment is measured against, and it need not be the domain in the visible `From`.
**`s=`** — The selector. The key is published at `<selector>._domainkey.<domain>`, which is what makes several keys able to coexist.
**`h=`** — The list of headers covered. A header not listed is not protected; a header listed but absent is treated as empty.
**`bh=`** — A hash of the body, so a truncated or altered body invalidates the signature independently of the headers.
**`c=`** — Canonicalisation. `relaxed` tolerates whitespace and header-case changes; `simple` tolerates almost nothing and breaks in transit far more often.
**`l=`** — An optional body-length limit. It permits content to be appended without breaking the signature, which is why publishing it is usually a mistake.

The `h=` list is the security-relevant choice. Sign `From`, `Subject`, `Date`, `To` and `Message-ID` at minimum: a signature covering only trivial headers verifies while leaving the parts that matter alterable.

## Why signatures break

| Cause | What happened | Whose problem |
|---|---|---|
| Mailing list footer | The body was appended to after signing | The list's; several sign again as themselves |
| Gateway rewriting | A scanner rewrote links or added a banner | The relaying organisation's |
| Header added or reordered | A hop inserted a header included in `h=` | Usually avoidable with `relaxed` canonicalisation |
| Key removed from DNS | The published record was deleted or the selector renamed | The sender's — often during a badly ordered rotation |
| Key too short | 1024-bit keys are increasingly refused | The sender's; 2048-bit is the current expectation |
| Encoding change | A hop re-encoded the body | The relaying hop's, and largely undetectable from the sender's side |

A failed signature is not evidence of forgery. It is evidence that the message is not byte-identical to what was signed, and the most common reason for that is an ordinary intermediary doing its ordinary job. Treating every DKIM failure as an attack produces a great deal of noise and very little safety.

> **Careful** A message may carry more than one signature, and each is verified independently. One failing while another passes is normal for list-relayed mail and is not itself a problem.

## Rotating a key without dropping mail

1. Publish the new public key under a **new selector**, leaving the old record in place.
   - Result: Both keys resolve. Nothing signed with either can fail for lack of a key.
2. Switch signing to the new selector.
   - Result: New mail carries the new selector; mail already in flight still verifies against the old record.
3. Wait out the longest plausible delivery delay — days, not hours — then remove the old record.
   - Result: The rotation completes with no window in which a signed message has no key to verify against.

The failure this sequence avoids is the obvious one done in the obvious order: replacing the key under the same selector. Every message signed with the old key and still queued anywhere then fails verification, and queued mail can be surprisingly old.

> **Note** Selector names should be meaningful rather than clever — a date or a provider name. Someone will read the record in two years and need to know what it is for.

## Does Connect use DKIM, and who signs?

**Educational, and signing belongs to your mail provider.** DKIM signing happens at the point mail leaves for the internet. Connect sends through the mailbox a workspace connected — Gmail, Microsoft Graph, or the business's own SMTP server — so the signature is applied by that provider using a key published under the business's own domain.

The corollary matters for anyone auditing an integration: **Connect does not publish DNS records for a customer domain and cannot.** SPF, DKIM and DMARC are configured by the business on its own domain. What connecting a mailbox to Connect changes about that setup is nothing — no new sending host is introduced, so no new authorisation is required.

Where Connect does contribute is upstream of authentication: compliance checks run in one place before any outreach, covering suppression, unsubscribe, complaints and do-not-contact, and the Assistant cannot clear a do-not-contact entry at all. Authentication proves a message came from an authorised route; those checks decide whether it should have been sent, which is the question that damages a domain when answered wrongly.

## Questions

### Does DKIM prove who wrote the message?

No. It proves that whoever holds the private key for that selector signed these headers and this body, and that neither has changed since. Authorship, intent and honesty are outside its scope, and a signed message can be entirely fraudulent if the signing domain is one the attacker controls — which is exactly why DMARC checks alignment with the visible `From`.

### Should a message carry both SPF and DKIM?

Yes. They fail in different situations: SPF breaks on forwarding, DKIM breaks when a relay modifies the message. DMARC passes when *either* aligns, so publishing both means an ordinary relay does not cost you authentication.

### How long should a DKIM key be?

2048-bit RSA is the current expectation, and 1024-bit is increasingly refused outright. Some providers offer Ed25519, which is shorter and faster but not universally verified — publishing it alongside an RSA key is the usual way to adopt it without losing verification anywhere.

## Related

- [SPF](https://connectbyjbrh.com/docs/technology/spf/)
- [DMARC](https://connectbyjbrh.com/docs/technology/dmarc/)
- [SMTP](https://connectbyjbrh.com/docs/technology/smtp/)
- [Suppression lists](https://connectbyjbrh.com/docs/technology/suppression/)
- [Credential rotation](https://connectbyjbrh.com/docs/technology/credential-rotation/)
- [Email in Connect](https://connectbyjbrh.com/docs/email/)

## What this page is based on

- RFC 6376 — DomainKeys Identified Mail (DKIM) Signatures, https://www.rfc-editor.org/rfc/rfc6376
- RFC 8463 — Ed25519 signing algorithm for DKIM, https://www.rfc-editor.org/rfc/rfc8463
- Connect channel source pack — docs-source/sources/CHANNELS.md §1, sending through the workspace's own mailbox and the single compliance checkpoint
- Connect capability registry (docs-source/facts.py) — suppression_dnc, imap_smtp; no DNS-record capability is registered
