Skip to content
All field notes

DKIM Key Rotation: Moving to 2048-bit Keys Without Breaking Mail

Move DKIM from 1024-bit to 2048-bit keys without failed signatures: new selectors, split TXT strings, overlap windows, and the Google and Microsoft quirks.

PlatOps Security TeamDeliverability8 min read
The short version
Never put a new key under an old selector. Publish the 2048-bit key under a new selector, confirm public resolvers return it, and only then switch signing.
A 2048-bit DKIM record is about 410 characters, and one TXT string holds 255. It has to be published as two or more quoted strings that receivers join with no spaces.
Keep the old public key unchanged for at least seven days after the switch (M3AAWG says up to 30), then revoke it with an empty p= instead of deleting it.
Microsoft 365 upgrades only the inactive selector per rotation, and each rotation takes 96 hours, so both selectors reach 2048 bits after two rotations.

A DKIM rotation that breaks mail almost never fails at the cryptography. It fails at DNS: a new key placed under the old selector while resolvers still cache the old one, a 410-character record the DNS panel would not take, a signer switched over before its record resolved, or a vendor selector nobody remembered was still on 1024 bits.

Selectors exist for this. RFC 6376 says they "make it possible to seamlessly replace public keys on a routine basis." Below is that procedure for keys you run, then for Google Workspace, Microsoft 365, and third-party senders. What is DKIM covers how a selector maps to a DNS name.

Why 1024-bit keys have to go

RFC 8301, section 3.2 sets the floor and the target: "Signers MUST use RSA keys of at least 1024 bits for all keys" and "Signers SHOULD use RSA keys of at least 2048 bits." A 1024-bit key still verifies. It is the minimum, not the recommendation.

The same RFC retires SHA-1: "rsa-sha1 MUST NOT be used for signing or verifying." A signer still on a 1024-bit key may be old enough to use it, so check the a= tag while you are there. It should read a=rsa-sha256.

The record tells you the key size. A 1024-bit RSA public key in base64 starts with MIGfMA0 and runs 216 characters. A 2048-bit key starts with MIIBIjAN and runs 392. The DKIM checker estimates the size of any selector you give it.

Inventory every selector first

DNS cannot list a domain's selectors. Aggregate reports show the ones in use: RFC 9990 makes the selector a required element of every DKIM result, "The selector that was used during validation (the "s=" tag in the signature)."

Pull 30 days of reports and list each signing domain and selector by source:

<dkim>
  <domain>example.com</domain>
  <selector>mail</selector>
  <result>pass</result>
</dkim>

Expect more than you remember: marketing, helpdesk, invoicing, a scanner relay. Each one is a separate rotation with a separate owner. Reading DMARC aggregate reports covers the rest of the XML.

Rotating a key you control

This covers signers you run: OpenDKIM, rspamd, an MTA with built-in signing. The timeline follows the M3AAWG DKIM Key Rotation Best Common Practices.

Day 0: publish the new key under a new selector

Do not reuse the old selector name. RFC 6376 is direct about it: "Signers are ill-advised to reuse selectors for new keys. A better strategy is to assign new keys to new selectors." The practical reason is caching: resolvers serve the old key until its TTL runs out, and mail signed with the new key fails until then.

M3AAWG suggests names that carry the stream, date, and size, such as "sales-201309-1024". Something like s202610 works. Generate the pair:

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out s202610.private.pem
openssl pkey -in s202610.private.pem -pubout -outform DER | openssl base64 -A

The DKIM generator does the same in your browser and splits the record for you.

The 255-character problem

v=DKIM1; k=rsa; p= plus a 2048-bit key is about 410 characters. A DNS TXT string "can be up to 256 characters in length (including the length octet)" (RFC 1035, section 3.3), so 255 of data. The record goes in as two or more strings inside one TXT record:

s202610._domainkey.example.com. 3600 IN TXT (
  "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."
  "...QIDAQAB" )

Per RFC 6376, section 3.6.2.2, strings "MUST be concatenated together before use with no intervening whitespace." Where a DNS panel does not split long values itself, Google's troubleshooting guide gives the manual fix: split the key into quoted strings and enter them one after another.

Read it back from two public resolvers:

dig +short TXT s202610._domainkey.example.com @1.1.1.1
dig +short TXT s202610._domainkey.example.com @8.8.8.8

The quoted strings should join into exactly the key you generated: no space at the joint, no stray quotes, nothing cut off.

Order matters here. Switch the signer before the record exists, and every receiver that looks up the selector caches the "no such name" answer. RFC 2308, section 5 sets that cache time from "the minimum of the SOA.MINIMUM field and SOA's TTL", so signatures keep failing for a while after you publish.

Day 1 to 2: switch signing

Once both resolvers return the record, point the signer at the new key: the KeyTable entry in OpenDKIM, the selector and key path in rspamd's dkim_signing.conf. Send a message to an outside mailbox and read the headers. You want s=s202610 and a=rsa-sha256 in DKIM-Signature, and dkim=pass in Authentication-Results.

Days 2 to 30: leave the old key alone

Mail signed with the old key is still in flight. Sending queues retry deferred mail for days: Postfix gives up after five by default (maximal_queue_lifetime). RFC 6376, section 5.2 also warns that "Verifiers can choose to defer validation, perhaps until the message is actually read by the final recipient." M3AAWG says to keep the old public key "unchanged in the DNS for a minimum of seven days, and up to 30 days."

Then revoke the old key

When the window closes, replace the old record with an empty key:

mail._domainkey.example.com. 3600 IN TXT "v=DKIM1; p="

RFC 6376, section 3.6.1 defines it: "An empty value means that this public key has been revoked." The RFC also allows removing the record. M3AAWG prefers the empty key: "Do not delete the selector entry for public key 1." A revoked selector tells receivers the key was retired on purpose.

A week later, the reports should show only the new selector for that source.

M3AAWG also recommends "pre-publishing the next public key in the DNS", so an emergency rotation after a key leak is a signer change with no DNS wait. Put the next routine rotation on the calendar: its guidance is that keys "should be rotated at least every six months."

If you would sooner not handle the DNS side by hand, DDMARC's hosted DKIM on the Professional plan generates the key pair and serves the public key from its own zone behind one CNAME. A rotation then mints a new selector, and you swap that one CNAME. The private key still goes on your signer.

Google Workspace

In the Admin console, go to Apps > Google Workspace > Gmail > Authenticate email and click Generate New Record with 2048 bits. Google's setup guide says: "If your domain already uses a DKIM key with the prefix google, enter a different prefix in this field." Mid-rotation, yours does. Use a new prefix, such as google2026, so the new record sits next to google._domainkey instead of replacing it.

Publish the record and confirm it resolves (Google says it "can take up to 48 hours for DKIM authentication to start working"), then click Start authentication. Leave google._domainkey published for the same overlap window before you revoke it. Our Workspace setup guide covers the first key.

Microsoft 365

Microsoft 365 uses two CNAMEs, selector1._domainkey and selector2._domainkey (see the setup guide), and a rotation swaps the keys behind them, so your DNS does not change. The upgrade has two catches. Microsoft's DKIM guide says "It takes four days (96 hours) for the new private key to start signing messages." And the Rotate-DkimSigningConfig reference says -KeySize 2048 upgrades only the selector that is not active, so you run it again after the rotation for the other one:

Rotate-DkimSigningConfig -Identity example.com -KeySize 2048
# after RotateOnDate passes, for the other selector
Rotate-DkimSigningConfig -Identity example.com -KeySize 2048
Get-DkimSigningConfig -Identity example.com | Format-List Selector1KeySize,Selector2KeySize,RotateOnDate,SelectorAfterRotateOnDate

Budget eight days. New-DkimSigningConfig still defaults to 1024 bits, so read Selector1KeySize and Selector2KeySize before assuming either selector is already 2048.

Third-party senders

M3AAWG puts the job with you: "The key rotation request must come from the organizational domain owner." How it runs depends on the setup.

CNAME delegation. You publish CNAMEs that point at the vendor, which can rotate behind them with no change to your DNS. M3AAWG's example uses three: "These three entries allow the third party to use one valid key while rotating the others." Ask the vendor how often it rotates and check the key size the target serves. Do not delete a CNAME that looks idle. It may hold the next key.

A TXT record you published. The vendor handed you a public key once, and it still sits in your zone at whatever size it had then. These are the selectors that stay on 1024 bits for years. Rotating one means asking the vendor for a new pair under a new selector and running the same publish, switch, wait, revoke sequence with them.

Ed25519 goes next to RSA, not instead of it

RFC 8463 says "verifiers MUST implement the Ed25519-SHA256 algorithm", and its 44-character keys fit in one TXT string. Its own transition section still has signers "add multiple signatures that use old and new signing algorithms", each under its own selector. Microsoft 365 signs with RSA only: its cmdlet reference says Ed25519 keys are not supported. Move to RSA 2048 first, then add an Ed25519 signature beside it where your signer supports one.

Questions we get asked

M3AAWG recommends keeping the old public key unchanged in DNS for at least seven days and up to 30 days after you switch signing, then revoking it by publishing the record with an empty p= value. Mail signed before the switch can sit in sending queues for days, and RFC 6376 allows verifiers to defer validation.

Field notes, twice a month.

When a mailbox provider changes the rules, you hear it here with the record you need to change. No digest, no roundup, no product news.

DMARC field notes, twice a month, from PlatOps Security, LLC (Gaithersburg, MD). We use your address only to send it. Unsubscribe with one click in any issue. Privacy policy.