mailrs-dkim
RFC 6376 DKIM signature verifier. Pairs with
mailrs-spf and
mailrs-rfc5322 to give
mailrs full ownership of the inbound email-auth stack — together
they replace the mail-auth umbrella crate with shape we control.
Quickstart
use ;
use TokioResolver;
# async
What this crate does (1.0)
- Parse
DKIM-Signature:headers (all tags: v, a, b, bh, c, d, h, l, q, s, t, x, i, z). - Canonicalization: simple/simple, simple/relaxed, relaxed/simple, relaxed/relaxed — all four combinations per RFC 6376 §3.4.
- Body hash computation (SHA-256) with optional length limit (
l=). - Header hash computation over the signed-header list in order,
with the DKIM-Signature value itself appended with the
b=tag cleared (RFC 6376 §3.7). - Public-key fetch: TXT at
<selector>._domainkey.<domain>. - Signature verification:
a=rsa-sha256(covers ~99% of real-world DKIM in 2026). - Returns the seven RFC 8601 vocabulary values:
none / pass / fail / neutral / temperror / permerror / policy. - Pluggable [
DkimResolver] async trait — bring your own DNS or use the bundled hickory-backed adapter.
What this crate does not (yet)
a=ed25519-sha256(RFC 8463) — modern but rare. Deferred to 1.1. The header parser rejects withUnsupportedAlgorithm; treat this asPermError.- Multiple signatures:
verifyfinds the first DKIM-Signature header. Most legitimate mail signs once; some ARC-bridged mail signs multiple times. The trait shape allows a futureverify_allwithout breaking changes. - DSN bounce signature verification — same protocol shape, but the DKIM-Signature is on a different header anchor; future addition.
- Author Domain Signing Practices — historical (RFC 5617), deprecated.
Why a new crate?
mail-auth includes DKIM but bundles it with SPF + DMARC + ARC. By
the project's DEPS_AUDIT we want each in a focused stone so:
- the perf of each step is measurable independently
- the API shape is tunable per-RFC
- the crate's transitive deps stay tight per use case
mailrs-spf shipped first (DEPS_AUDIT #1). This is its sibling.
Performance
Measured (criterion, M-series Mac, release):
| Operation | Median |
|---|---|
DkimHeader::parse (minimal header) |
147 ns |
DkimHeader::parse (realistic 11-tag header) |
405 ns |
canonicalize_body (simple) |
70 ns |
canonicalize_body (relaxed) |
140 ns |
canonicalize_header (relaxed, one header) |
85 ns |
Vs. mail-auth 0.9 (the de-facto Rust competitor)
| Input | mailrs-dkim 1.1.3 | mail-auth 0.9 | Winner |
|---|---|---|---|
| minimal (7 tags) | 147 ns | 167 ns | mailrs +12% ✅ |
| realistic (folded, 11 tags) | 405 ns | 423 ns | mailrs +4% ✅ |
We beat mail-auth on both inputs. The 4.6× / 3.5× cumulative speedup
since 1.1.1 came from: (1) single-pass byte scanner replaces HashMap +
unfold pre-pass; (2) byte-level tag dispatch via match name.as_bytes()
(lowercase fast path + case-insensitive fallback); (3) h= signed-
headers parsed via byte-iter with from_utf8_unchecked (safe because
only ASCII-lowercased bytes are pushed). Reproduce via
cargo bench -p mailrs-dkim --bench compare_mail_auth.
Production verify is dominated by:
- DNS lookup for the selector key (5-50 ms)
- RSA-SHA256 signature verification (~1-2 ms for 2048-bit keys)
The bench numbers above are the pure CPU pieces. Reproduce:
cargo bench -p mailrs-dkim --bench dkim.
Stone audit (v3 cycle, 2026-05-25)
| Axis | Status |
|---|---|
| doc | ❌ 2 errors, 0 warnings (cargo doc --no-deps -p mailrs-dkim) |
| test | line cov: 85.1% (cargo llvm-cov -p mailrs-dkim --summary-only) |
| bench | ✅ 2 file(s) criterion + ✅ 5 gate(s) perf_gate.rs |
| size | release rlib: 2.5 MB |
| fuzz | ✅ 2 target(s) |
| mem | dhat profile pending (v3.4 backlog) |
Competitor comparisons (from PERFORMANCE.md)
mailrs-dkimvsmail-auth0.9 (DKIM-Signature header parse)
License
Apache-2.0 OR MIT.