IP reputation is arithmetically dead on IPv6. Let the sender declare the unit.
SwornMail lets a sending operator publish a signed, verifiable claim: this IPv6 prefix is one accountable entity, and we stake our domain name on it.
The problem
One allocation. Eighteen quintillion addresses.
A single IPv6 /64 — the ordinary subnet boundary, the one every SLAAC network uses — contains 18,446,744,073,709,551,616 addresses.
Blocklists cannot converge
A sender rotating source addresses never repeats one. Per-address listings never catch up, and per-address lookups approach a 100% cache-miss rate — degrading the blocklist infrastructure itself.
Aggregating is a guess
Aggregate at /64 and you punish shared infrastructure. Aggregate wider and you punish an entire provider for one tenant. Since RFC 9977, an address holder can publish how large its end-sites are — the size of the unit. It still does not tell you who is accountable for one.
So IPv6 mail gets treated as suspect
Receivers respond to an unanswerable question with blanket caution, and IPv6 senders face checks IPv4 senders do not. Microsoft 365, for one, may need the receiving organisation to opt in before it takes anonymous IPv6 mail at all, and then accepts it only from addresses with reverse DNS whose mail passes SPF or DKIM. That is a standing disincentive, at a point where about half of the users reaching Google already do so over IPv6.
The missing fact
Who is accountable for a range of addresses is an administrative fact. The mail operator knows it. The receiver cannot see it at connection time, and nothing in the mail stack carries it.
How it works
The operator states the boundary, and signs their name to it.
Two DNS TXT records. Receivers verify at connection time, before message data, and key reputation on (operator domain, observed /64) instead of on individual addresses.
Sending operator
mailer.example.com
_prefixes._sworn.mailer.example.com. IN TXT "v=SWORN1; p=2001:db8:f00::/48; u=64"
2026a._sworn.mailer.example.com. IN TXT "v=SWORN1; k=ed25519; pk=…"
- Declares the prefix it stands behind
- Declares the unit receivers should aggregate at (
u=64) - Stakes the domain’s own reputation on both
Receiving MTA
connection from 2001:db8:f00:1234::25
- Discover the operator accountable for the source address
- Fetch and verify their published policy
- Confirm the address really falls inside the attested prefix
- Key reputation on
2001:db8:f00:1234::/64
Verification is stateless and O(1) per connection, with no verifier-initiated fetch to attacker-named endpoints beyond DNS.
Two modes
DNS-only. Publish the records; nothing in your mail software changes. Receivers discover the operator from the connecting address. This is deployable today and is the baseline the protocol is designed around.
Signed token. An SMTP extension carries a compact signed token verified statelessly at connection time, for stronger source authenticity. Optional, and it requires software that speaks the extension.
Attestation is accountability, not endorsement. Publishing a record does not ask anyone to trust you. It says who to hold responsible. Receivers and reputation services decide what that is worth — and SwornMail is fail-open by design: its absence or failure must never make treatment worse than a receiver’s existing default for unattested IPv6, for reputation or for delivery.
Deploy
Three commands and two DNS records.
Real output from the sworn CLI, trimmed for length: the key is shortened where it repeats, the token is elided, and the DNS-panel forms and next-step hints are left out. Addresses are from the documentation range 2001:db8::/32.
1. Generate a signing key
$ sworn keygen --selector 2026a
selector 2026a
private key 2026a.key (mode 0600 — keep it secret, back it up)
public key dI6VtBXnxGKWqjtrL3rzidPUDEhrKGJXDuVTd3Soco0=2. Generate the records
$ sworn genrecord --domain mailer.example.com --selector 2026a \
--key 2026a.key --prefix 2001:db8:f00::/48 --unit 64
Publish these records for mailer.example.com.
1. key record — the signing key receivers fetch
zone file:
2026a._sworn.mailer.example.com. 3600 IN TXT "v=SWORN1; k=ed25519; pk=dI6VtBX…co0="
2. policy record — the prefixes you stand behind
zone file:
_prefixes._sworn.mailer.example.com. 3600 IN TXT "v=SWORN1; p=2001:db8:f00::/48; u=64; t=y"
3. reverse-tree pointer (optional) — publish in your reverse zone if you
control it; otherwise discovery uses your MTA's forward-confirmed PTR
_sworn.0.0.f.0.8.b.d.0.1.0.0.2.ip6.arpa. 3600 IN TXT "v=SWORN1; d=mailer.example.com"
notes:
- t=y is set, so this is observe-only: receivers report sworn=none policy.testing=y
and stake no reputation on you, for credit or blame. Watch your traffic, then
re-run with --testing=false to accept accountability.The command also prints a DNS-panel form of each record, for providers without zone-file editing, and --json for a provider API.
3. Publish them, then check from anywhere
$ sworn record mailer.example.com --selector 2026a
$ sworn discover --ip 2001:db8:f00:1234::25What it looks like when it works — and when it does not
$ TOKEN=$(sworn sign --key 2026a.key --selector 2026a \
--domain mailer.example.com --prefix 2001:db8:f00::/48)
$ sworn verify $TOKEN --ip 2001:db8:f00:1234::25 \
--policy 'v=SWORN1; p=2001:db8:f00::/48; u=64' --key dI6VtBX…co0=
sworn=pass op=mailer.example.com unit=2001:db8:f00:1234::/64 observed=2001:db8:f00:1234::/64
$? 0
# the same token, presented from outside the attested prefix
$ sworn verify $TOKEN --ip 2001:db8:999::25 \
--policy 'v=SWORN1; p=2001:db8:f00::/48; u=64' --key dI6VtBX…co0=
sworn=fail reason=off_prefix
$? 1A stolen key alone buys little: it can sign only for prefixes the operator’s published policy already authorises, and a token verifies only from inside the prefix it names.
Integrations
A Postfix milter and an rspamd module are available for the receiving side. We wrote both; neither implies any involvement by, or endorsement from, the Postfix or rspamd projects.
Full operator guide → on swornmail.dev, including every record tag and what to check before leaving observe-only mode.
Before you commit to anything
Publish t=y and stake nothing.
Testing mode is not a flag you have to find. It is what the tooling publishes unless you explicitly turn it off.
An operator in testing mode whose checks would all pass is reported as sworn=none policy.testing=y instead of pass; a failing check is still reported as a failure. Conforming receivers stake no reputation on them in either direction — not credit, not blame. You can watch how your traffic would be classified without having accepted accountability for anything.
When you are satisfied, re-run genrecord with --testing=false and publish the updated record. That single change is the moment the oath is actually taken, and it is entirely yours to make.
This is enforced, not advisory. A testing-mode operator being reported as passing is treated as a conformance bug in this project — the observe-only on-ramp is worthless if implementations score you anyway.
Relationship to what already exists
It attests the connection, not the message.
SwornMail replaces nothing. SPF, DKIM and DMARC answer questions about a message and the domain it claims; RFC 9977 publishes how address space is divided. SwornMail answers a question none of them ask.
| Mechanism | What it authenticates | The question it answers |
|---|---|---|
| SPF | The sending host, against a domain’s published list | “Is this host authorised to send for the domain this message claims?” |
| DKIM | The message content, cryptographically | “Was this message signed by the domain it claims, and unmodified since?” |
| DMARC | Alignment and policy | “Do those results line up with the visible From:, and what should I do if not?” |
| RFC 9977 | An address holder’s published end-site size, optionally RPKI-signed | “How large is one end-site in this range?” |
| SwornMail | The connection’s address space | “Which addresses are one accountable entity, so I have something stable to keep reputation on?” |
“Doesn’t SPF already list IPv6 ranges?” It does — and that is a fair objection to raise first. The difference is what the range is for. An SPF range authorises hosts for a domain a message claims, and is only meaningful once you have a claimed identity to check it against. SwornMail’s prefix is an assertion about the address space itself: it gives you a stable reputation key at connection time, including for a sender whose domain you have never seen before, and it names who has volunteered to be held responsible for it.
Adoption
No public deployments yet.
SwornMail is new. We are not going to pretend otherwise on the page where you are deciding whether to believe us.
What does exist
- A frozen
-01wire format with 85 published conformance vectors - Two independent implementations — Go and Rust — cross-checked by a differential harness
- A sender CLI, a Postfix milter, and an rspamd module, all written by us
- Apache-2.0, with a patent pledge
What we want
Operator feedback, more than adoption. If you run mail on IPv6 and this is wrong, impractical, or solves a problem you do not have, that is the most useful thing you could tell us right now.
Status and limitations
What is settled, and what is not.
Settled
- The
-01wire format is frozen: token bytes, record syntax, and the conformance vectors are a public contract. - 85 conformance vectors (48 token, 27 record, 10 policy authorisation), published in the spec repository.
- Two implementations agree. A differential harness generates an adversarial corpus and runs both verifiers over it — 3,059 cases at the default setting, zero accept/reject or result divergences. A second harness cross-checks record parsing between the Go and Lua implementations across 259 cases, also with zero divergences.
- Apache-2.0. A provisional patent exists specifically to keep the mechanism open, with a published pledge never to assert it against implementations.
Not settled
- This is not an IETF standard. It is an Internet-Draft, and one that has not yet been submitted. Nothing here is an RFC and nothing here has IETF consensus.
- No public deployments. Nobody is running this in production, including us.
- DNS-only mode is experimental in the current revision: receivers should give it low weight until there is operational experience.
- The SMTP extension mode needs software that speaks the extension; a milter cannot advertise it, because milters run after the command phase.
- Post-quantum signatures are designed for but not yet registered.
The differential figure above is reproducible rather than a marketing number. The corpus size is a parameter of the harness; run it yourself with a larger fuzz count and the divergence count should stay at zero. If it does not, that is a bug worth reporting.
Get involved
The useful thing you can do is disagree with us.
Especially if you run mail at scale on IPv6, and especially if you think this is wrong.
Argue with it
- val@sworn.email
- Open an issue on the spec
- IETF: the draft is headed for the
mailmaintworking group