Skip to content

Verify inbound DKIM2 and report it beside DKIM - #23

Open
Baker wants to merge 1 commit into
mainfrom
feat/dkim2-inbound
Open

Baker wants to merge 1 commit into
mainfrom
feat/dkim2-inbound

Conversation

@Baker

@Baker Baker commented Nov 8, 2026

Copy link
Copy Markdown
Owner

Summary

Inbound mail can now be checked for DKIM2 (draft-ietf-dkim-dkim2-spec-09) in addition to SPF, RFC 6376 DKIM, and DMARC.

  • Verification uses github.com/croessner/dkim2 v0.3.3. One verifier is built at startup and reused. The server verifies only; it does not sign.
  • The SMTP envelope is included. A null MAIL FROM ("" from go-smtp) is sent as <>, and bare addresses are wrapped as <addr>. Local-parts stay case-sensitive.
  • Results are reported on the webhook as authentication_results.dkim2, next to the existing dkim object. result is none when the message has no DKIM2 fields, otherwise pass, fail, temperror, or permerror. A canceled check is temperror with reason unavailable, so the webhook still gets a value. The signing domain is not included. A passing signature set omits the selector.
  • DKIM2 does not accept or reject the message, and it is not an input to DMARC. DMARC still uses SPF and RFC 6376 DKIM only.
  • Enabled by default. Turn it off with -enable-dkim2 or ENABLE_DKIM2.
  • Metrics: dkim2_results_total (labels result and reason, not domain) and dkim2_check_duration_seconds.

Messages with no DKIM2 fields return before any DNS lookup. A message that does verify looks up the public key, and, only after every signature proof passes, the draft-09 From-domain policy.

Test plan

  • go test ./...
  • Unsigned message reports none
  • Committed Ed25519 fixture verifies as pass against a stub key, including a null sender <>
  • Missing key reports permerror / missing_key
  • MAIL FROM mismatch, local-part case, and an extra recipient report fail / envelope_mismatch
  • Canceled context reports temperror / unavailable and still returns a result
  • Fixture files stay CRLF in git so the body hash survives checkout
  • Send a message with no DKIM2 fields and confirm the webhook dkim2.result is none and DMARC is unchanged
  • Send a DKIM2-signed message and confirm the webhook carries state, reason, scope, checks, and signature facts, with no signing domain

Made with Cursor

Draft-09 results stay off the RFC 6376 and DMARC paths, and the signed fixtures keep the CRLF bytes their hashes cover.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant