DKIM Signing
DKIM (DomainKeys Identified Mail) is an email authentication mechanism that allows a mailserver to digitally sign outgoing emails for a domain. Receiving mail servers can verify this signature using a public key published in DNS to confirm the message was authorized by the domain and was not modified during transit.
How DKIM works in practice
1. bob@bar.example sends an email to alice@foo.example. The sending
mail server for bar.example selects one or multiple DKIM keys using a
selector (e.g., mail) and creates one or multiple cryptographic
signature for selected headers and the message body, adding a DKIM-Signature
header that references the selector.
2. The message arrives at foo.example. The receiving mail server reads the
DKIM-Signature headers, looks up the public keys for bar.example for
each of the specified selectors (e.g., mail._domainkey.bar.example), and
verifies that at least one signature matches the message content.
3. With a valid signature, the receiver knows the message was authorized by
bar.example and that the signed headers and body were not modified in
transit. If the content or signed headers were changed, the DKIM verification
fails. The use of selectors allows bar.example to rotate or migrate keys
without disrupting verification for previously sent messages.
Enabling DKIM Signing
Because DKIM signing is crucial for reliable mail delivery it is enabled by
default and without further configuration a DKIM keypair will be generated for
each mailserver.domains (including mailserver.srs.domain,
if set) based on mailserver.dkim.defaults.
{
mailserver = {
domains = [ "example.com" ];
dkim.enable = true; # enabled by default
};
}
Note
If you set up NixOS Mailserver before the 25.11 release your DKIM keys were generated with 1024 bit RSA and we recommend replacing them with 2048 bit RSA key material per RFC8301 3.2.
DKIM Key Rotation
DKIM key rotation replaces a domain's signing keys to maintain strong email authentication and support algorithm upgrades. Rotation is essential for migrating away from weaker or deprecated algorithms.
Selectors allow multiple keys to coexist during the transition: a new key can be deployed under a different selector while the old key remains valid for a limited period to verify messages still in transit. Once all messages signed with the old key have been delivered, the key can be safely retired, ensuring a reliable migration without breaking verification.
1. Make the automatically generated key explicit
First we need to make sure we keep the current DKIM key configured. If you were relying on automatically generated keys before, you now need to start explicitly defining that key, because explicit selector configuration takes precedence.
{
mailserver = {
domains = [ "example.com" ];
dkim.domains = {
"example.com".selectors = {
"${config.mailserver.dkim.defaults.selector}" = { };
};
};
};
}
2. Create the new DKIM keypair
Next we need to create a new DKIM key with a unique selector, you can
for example choose the current date. Without any settings passed a new
key will be generated from the current mailserver.dkim.defaults, which should be sufficient.
{
mailserver = {
domains = [ "example.com" ];
dkim = {
enable = true;
domains."example.com".selectors = {
"${config.mailserver.dkim.defaults.selector}" = { };
"rsa-2026-03" = {
keyType = "rsa";
keyLength = 2048;
};
};
};
};
}
Warning
While DKIM does support Ed25519 keys (RFC8463), many validators still lack proper support and may treat Ed25519 key material as invalid. As a result, mail signed only with Ed25519 DKIM keys may fail verification at some receivers.
Once this configuration is applied the new keypair will be generated below
mailserver.dkim.keyDirectory, which defaults to /var/dkim. The
mailserver then begins signing outgoing mail with this key, so that it is now
signing with two DKIM keys simultaneously.
To allow receiving servers to verify the new DKIM signature its
public key needs to be published into DNS. Look up the public key from
/var/dkim/example.com.rsa-2026-03.txt and create the following DNS record by
substituting selector and public key.
Name |
TTL |
Type |
Value |
|---|---|---|---|
rsa-2026-03._domainkey.example.com. |
86400 |
TXT |
v=DKIM1; k=rsa; p=<public key> |
Note
If you created an Ed25519 key, make sure to set the correct key type: k=ed25519
Now wait for a few minutes and then check DNS propagation to show the value specified.
$ nix-shell -p dig --command "dig @ns1.example.org TXT rsa-2026-03._domainkey.example.com"
You can use https://www.mail-tester.com to test the new DKIM signature passes
validation. They allow you to view the message source where you can check that
the correct number of DKIM-Signature keys are present in the mail header.
3. Stop signing with the old DKIM keypair
Once validation passes we need to stop signing with the old DKIM keypair, so mail in transit eventually stops depending on the key material we want to rotate out. Removing the selector will not remove the key material from disk, but it will stop using it to sign outgoing mail.
{
mailserver = {
domains = [ "example.com" ];
dkim = {
enable = true;
domains."example.com".selectors = {
"rsa-2026-03" = {
keyType = "rsa";
keyLength = 2048;
};
};
}
}
}
Apply the configuration.
4. Remove the old DKIM selector from DNS
Warning
Do not remove the DNS records for the old selector immediately. Keeping them in place is essential to ensure that messages still in transit can be verified and delivered successfully.
Mail delivery is not always instantaneous. In the worst case, multiple retries over several days may be required. According to RFC5321 4.5.4.1 delivery should be retried for at least 4-5 days.
This means messages signed only with the old DKIM key could still be in transit and rely on the old selector to verify their signatures. To ensure reliable delivery, we recommend waiting at least five days before removing the old DKIM selector from DNS.