DKIM Key Length: RSA-1024 vs 2048 vs Ed25519 and the 255-Byte DNS Wall
DKIM key sizing is a DNS packet-size problem before it is a cryptography problem. Here is why RSA-2048 is the pragmatic default, why 4096 quietly breaks resolvers, and how Ed25519 plus dual-signing is the correct 2026 answer.
EvilMail TeamJuly 16, 202611 min read
Your DMARC aggregate reports show a thin but persistent stream of dkim=fail, and every few thousand messages a dkim=temperror. The signature is correct. The private key is fine. The selector matches. What actually happened is that your 2048-bit public key got pasted into a DNS panel that split it across two TXT strings wrong — or worse, someone "hardened" it to 4096 and the answer no longer fits in a UDP packet, so resolvers behind a broken middlebox fall back to TCP, fail, and report a temporary error that looks random.
Here is the whole thing in one sentence: DKIM key sizing is a DNS record-size and interop problem first, and a cryptography problem a distant second. Nobody is factoring your modulus. Your mail is failing because of a length-prefix byte in RFC 1035.
The three choices, and what they actually cost
The honest comparison is measured in the only unit that matters here — the base64 length of the p= tag you have to publish.
RSA-1024 — public key ≈ 216 base64 chars. Fits in a single TXT string trivially. But it is the deprecated floor: NIST SP 800-57 retired 1024-bit RSA years ago, and Gmail treats sub-1024 keys as an outright fail and 1024 as weak. Do not deploy it new.
DKIM Key Length: RSA-2048 vs Ed25519 vs 4096 and DNS TXT Limits — EvilMail Blog
RSA-2048 — ≈ 392 chars. This is the interoperable default, and it is also the *first* size that crosses the 255-byte single-string boundary. Every verifier on earth understands it. Its only cost is that you must publish it as a multi-string record.
RSA-4096 — ≈ 736 chars. Always multi-string, always pushes the DNS answer toward the size where TCP fallback matters. The security upside over 2048 is marginal for a key you rotate quarterly; the interop downside is real. Skip it.
Ed25519 — a 32-byte key, ≈ 44 base64 chars. Tiny record, one clean string, fast signing and verifying. Standardized for DKIM in RFC 8463 (k=ed25519, algorithm ed25519-sha256). The catch: not every verifier in 2026 checks it, so you cannot ship it alone.
The recommendation, up front so you can stop reading if you want: Ed25519 plus RSA-2048 dual-sign for anything greenfield; RSA-2048 alone if your tooling can't dual-sign. RSA-4096 is a trap.
Why 255 bytes is the number that rules everything
A DNS TXT record is not a single string. It is a sequence of *character-strings*, and each one is length-prefixed by a single byte. One byte maxes out at 255. So no individual character-string in a TXT record can exceed 255 bytes — a hard structural limit from RFC 1035, not a policy you can raise.
An RSA-2048 public key in p= is ~392 characters. It physically cannot live in one character-string. It must be published as two (or more) quoted strings that the resolver concatenates back together with no separator:
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...255 chars" "...remaining base64 of the key..."
The two quoted strings glue edge to edge. There is no space, no comma, no newline between them — the resolver joins the raw bytes. Get that wrong (a stray space inside the quotes, a + mangled into a space, a UI that only saves the first string) and the reconstructed key is garbage, and verification fails with dkim=fail.
That is cliff one. Cliff two is on the wire. Classic DNS over UDP caps the payload at 512 bytes. EDNS0 raises that, but a large TXT answer — a 4096-bit key, or a 2048 key sharing the name with SPF and other TXT records — can push the response past what the path allows, forcing a TCP fallback. Plenty of corporate resolvers, captive portals, and aging middleboxes silently drop DNS over TCP. The verifier can't fetch the key, and instead of a clean fail it emits dkim=temperror — a *temporary* error. Your monitoring sees an intermittent, un-reproducible failure that correlates with nothing. That is the 4096-bit key you deployed "to be safe."
Reading a real DKIM TXT record
Strip a DKIM record down and only a few tags matter:
k=rsa — key type. Omit `k=` and it defaults to `rsa`. For Ed25519 you must write k=ed25519 explicitly.
p= — the base64 public key. An empty value (p=) means the key is revoked; verifiers treat it as a hard fail on purpose.
t=y — testing mode; verifiers are told not to treat a failure as meaningful. Useful while you validate, but remove it once the key works, or you have effectively disabled enforcement. t=s locks the signature to the exact domain (no subdomain i=).
The Ed25519 equivalent is almost boringly small — one string, done:
This drops 2026a.private (the signing key) and 2026a.txt (the ready-to-publish TXT record, already split into quoted strings) in /etc/opendkim/keys/evilmail.pro/. Copy the contents of the .txt file into DNS verbatim.
Dual-signing means running two selectors on outbound mail — say 2026a (k=rsa) and 2026a-ed (k=ed25519) — and publishing both records. In OpenDKIM you list both in the KeyTable/SigningTable; rspamd's dkim_signing module takes a selector_map or per-domain selectors array with one entry per key type. Every verifier picks the strongest algorithm it understands: RFC 8463-aware ones use Ed25519, everyone else uses RSA. You lose nothing and gain forward coverage.
Verifying before you trust it
Never trust a freshly published record. Query it and reassemble:
bash
dig +short TXT 2026a._domainkey.evilmail.pro
dig prints the record back as separate "..." quoted chunks — concatenate them (drop the quotes and the space between) to see the real key. Then let the signer sanity-check itself against live DNS:
bash
opendkim-testkey -d evilmail.pro -s 2026a -vvv
You want key OK. A key not secure note just means no DNSSEC and is fine.
The ground truth is a live probe. Send to a Gmail or Outlook address, open the raw message, and read Authentication-Results:
Two dkim=pass lines carrying header.a=ed25519-sha256andrsa-sha256 prove both signatures verified and confirm exactly which algorithm the receiver actually used. During any change, account for DNS propagation and cached negative answers — give it a TTL cycle before concluding anything.
Rotation, and the mistakes that cause outages
DKIM keys have short useful lives, so rotating every 3 to 6 months is plenty. Rotation, not key length, is your real defense: a 2048-bit key you replace quarterly is safer in practice than a 4096-bit key you set in 2021 and forgot.
The overlap window is the part people get wrong:
1.Generate a new selector (2026b) and publish its TXT record.
2.Switch signing to 2026b.
3.Keep `2026a`'s record live until all in-flight and queued mail signed with it has been delivered and verified — usually a day or two.
4.Only then remove the 2026a record.
Yank the old record too early and mail still sitting in a receiver's queue fails DKIM on delivery. And never reuse a selector name — once retired, a selector stays dead, because you can't be sure old signed mail isn't still floating around referencing the old key. To hard-revoke a compromised key, publish it with an empty p= rather than deleting the record, so verifiers get an explicit revocation instead of a lookup miss.
Checklist
Use RSA-2048 as your minimum and default. Never RSA-1024 for new keys.
Add an Ed25519 dual-sign selector wherever you can — it costs nothing and future-proofs you.
Keep every TXT character-string ≤ 255 bytes and verify the concatenation reassembles the exact key.
Confirm DNS over TCP works end-to-end before publishing any oversized answer.
Use date-based selectors (2026a, 2026b) so rotation state is obvious.
Rotate every 3–6 months with an overlap window; never reuse a selector.
Validate with dig + opendkim-testkey + a live probe reading Authentication-Results.
Drop `t=y` once the key verifies.
Do not publish RSA-4096 unless you have personally proven your resolver path survives TCP fallback.
Operator's rule of thumb: if your key doesn't fit in a single 255-byte string, the risk you just took on lives in DNS, not in the math — size for the resolver, sign twice, and rotate on a calendar.