Skip to content
SwornMail docs

Implementations

Libraries and integrations

All Apache-2.0, all written by the protocol author. Two independent verifiers exist specifically so the wire format is pinned by agreement rather than by one codebase’s habits.

WhatLanguageWhere
Reference library, CLI, milterGoswornmail/swornmail-go
Independent verifierRustswornmail/swornmail · crates.io
rspamd moduleLuaswornmail/rspamd-swornmail
Draft, threat model, vectorsswornmail/spec

Go — reference implementation

$ go get github.com/swornmail/swornmail-go
$ go install github.com/swornmail/swornmail-go/cmd/sworn@latest

sworn.Verify checks Mode 2 tokens; sworn/discover runs Mode 1 discovery. The resolver is an interface, so both are testable without DNS and can be pointed at a validating resolver in production.

Dependencies are deliberately few: fxamacker/cbor, veraison/go-cose, and emersion/go-milter for the milter. Otherwise standard library.

Postfix milter

cmd/sworn-milter performs per-connection Mode 1 discovery and stamps Authentication-Results. It strips inbound AR fields at the trust boundary, and it is strictly fail-open — it never rejects a message.

A milter cannot carry Mode 2. Milters run after the command phase, so they cannot advertise an EHLO keyword or take an SMTP verb. Mode 2 needs an MTA that speaks the extension, or a proxy in front. This is a real limitation, not an oversight.

Rust — independent verifier

Written from the draft rather than ported from the Go code, which is the entire point: an implementation derived from another implementation cannot detect that the draft is ambiguous. Writing it independently surfaced three real draft/implementation contradictions before the format was frozen.

Lua — rspamd module

A self-contained rspamd module, informational by default and fail-open. Its protocol logic makes no rspamd calls — the resolver is injected — so it runs under plain Lua and can be driven by the differential harness.

Conformance

The -01 wire format is frozen. Token bytes, record syntax and the conformance vectors are a public contract with shipped implementations behind them.

Test vectors

62 vectors — 48 token, 14 record — published at spec/test-vectors. They are authored from the draft, never derived from an implementation: a vector generated by the code it is meant to check certifies nothing. An earlier round of vectors was circular in exactly that way, and rebuilding them found real defects.

Differential harnesses

Two harnesses generate adversarial corpora and run two implementations over them, comparing results:

# tokens: Go vs Rust
$ go run ./cmd/difftest --rust ../swornmail/target/debug/difftest

# records: Go vs Lua
$ go run ./cmd/recorddiff --arm ../rspamd-swornmail/test/difftest.sh

Both report zero divergences. The token corpus size is a parameter — --fuzz defaults to 3000, giving 3,048 cases — so the figure is reproducible rather than a marketing number. Run it larger; the divergence count should stay at zero. If it does not, that is a bug worth reporting.

Both harnesses expect the repositories to be siblings on disk. Clone them into one directory.

Writing your own

Start from the draft, not from this site and not from an existing implementation. Then run the vectors. If you disagree with a vector, that is worth an issue — it means either the draft is ambiguous or a vector is wrong, and both are defects worth fixing before anyone else hits them.