Issue Description
Per-domain Ed25519 DKIM signatures generated by Stalwart consistently fail verification at Gmail while the RSA signature on the very same message verifies cleanly. The published Ed25519 public key in DNS matches the public key stored in the server’s DkimSignature object byte-for-byte, so this is not a DNS publish issue.
DMARC overall still passes thanks to the RSA signature, so this is currently cosmetic — but it produces a steady dkim=fail line in every DMARC aggregate report Google returns, across every domain we run.
Previously filed as GitHub issue #3193 (auto-closed by the triage bot with a request to repost here).
Expected Behavior
Both DKIM signatures Stalwart emits for a message (Ed25519 and RSA) should verify against their respective published public keys at the receiver. RFC 8463 §3 says verifiers MUST treat valid Ed25519 signatures as authoritative, and the published Ed25519 key in DNS already matches the server’s stored key.
Actual Behavior
For the same outbound message: - RSA selector v1-rsa-20260601 → dkim=pass at Gmail - Ed25519 selector v1-ed25519-20260601 → dkim=fail at Gmail
Same canonicalisation (relaxed/relaxed), same signed headers (From, To, Date, Subject, Message-ID), same body. Reproduced across 7 different tenant domains; Ed25519 selectors were created independently between 2026-05-21 and 2026-06-03, every one of them fails the same way.
Sample DMARC aggregate fragment from Google:
xml <auth_results> jabali-panel.com fail v1-ed25519-20260601 jabali-panel.com pass v1-rsa-20260601 jabali-panel.com pass </auth_results>
Relevant Log Output
Add any new domain in Stalwart on a host with a public IP. Stalwart auto-generates one Ed25519 + one RSA DkimSignature for it.
Publish both DKIM TXT records (and the matching SPF + DMARC) at the DNS provider.
Send mail from @ to any Gmail address.
Wait for the daily DMARC aggregate report from [email protected], or inspect the Authentication-Results header on the delivered Gmail message.
Observed: dkim=fail for the Ed25519 selector, dkim=pass for the RSA selector, on the same message.
Relevant Log Output
No relevant errors in the Stalwart log — signing succeeds without warning, both signatures are emitted, and the message is accepted by Gmail (DMARC=pass overall via the RSA signature). The failure is visible only on the receiver side via the DMARC aggregate report shown above.
Verified pieces on our end:
Check Value
DNS pubkey at v1-ed25519-20260601._domainkey.jabali-panel.com v=DKIM1; k=ed25519; p=TSI1vcJ8BNeVHc4ArJ7aJs7f+sCs/CgukmF3S84t5Ws=
Stalwart DkimSignature.publicKey for that selector TSI1vcJ8BNeVHc4ArJ7aJs7f+sCs/CgukmF3S84t5Ws= (byte-identical)
@type Dkim1Ed25519Sha256
canonicalization relaxed/relaxed
headers From, To, Date, Subject, Message-ID
Source IP server itself (no third-party relay)
Independent Ed25519 keys across multiple domains and dates all fail identically — rules out single-key bit-rot
I’m happy to capture an outbound message via a one-shot MtaRoute to a local netcat listener and attach the full signed payload + canonicalised body bytes for a deterministic local repro — let me know if that would help and I’ll post it as a follow-up.
Stalwart Version
v0.16.x
Installation Method
Binary (Linux)
Database Backend
RocksDB
Blob Storage
RocksDB
Search Engine
Internal
Directory Backend
Internal
Additional Context
7 tenant domains, every one shows the behaviour.
No upstream relay; outbound goes directly from Stalwart to recipient MX.
I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.
on
I have searched this support forum (open and closed topics) and confirm this is not a duplicate.
on
I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.
on