Atmosphere Mail#
A cooperative email reputation layer for atproto. PDS operators pool sending volume and reputation through shared infrastructure, verified by a labeling service that checks DNS configuration and publishes signed attestations to the atproto network.
Starting with transactional email (verification codes, password resets, notifications) to build collective domain reputation, with the long-term goal of making self-hosted personal email viable again.
See atmosphere-mail-vision.md for the full proposal.
Status#
Phase 0: labeler service (local development, not yet deployed).
How it works#
- A PDS operator publishes an
email.atmos.attestationrecord declaring their mail domain and DKIM selectors - The labeler watches the atproto firehose (via Jetstream) for these records
- For each attestation, it verifies:
- Domain control — the operator's DID handle matches the domain, or a
_atproto.<domain>TXT record points to the DID - MX — at least one MX record exists
- SPF — a
v=spf1record exists without+all - DKIM — every declared selector has a
v=DKIM1record - DMARC — a record exists at
_dmarc.<domain>with policy quarantine or reject
- Domain control — the operator's DID handle matches the domain, or a
- If all checks pass, the labeler signs and publishes
verified-mail-operator(and optionallyrelay-member) labels on the operator's DID - Labels are queryable via standard atproto XRPC endpoints (
com.atproto.label.queryLabels,com.atproto.label.subscribeLabels) - A scheduler re-verifies every 24 hours and negates labels if DNS degrades
Lexicons#
The NSID namespace is email.atmos.*, backed by atmos.email. See lexicons/README.md for schemas and open questions.
Building#
go build ./cmd/labeler
Running#
Initialize state directory and signing key:
./labeler -init
This creates ./state/config.json (if missing) and generates a secp256k1 signing key. The labeler's did:key is printed to stdout.
Start the labeler:
./labeler -config ./state/config.json
Configuration#
Copy config.json.example to ./state/config.json. All fields have defaults:
| Field | Default | Description |
|---|---|---|
listenAddr |
:8081 |
XRPC server bind address |
stateDir |
./state |
SQLite database and key storage |
jetstreamURL |
wss://jetstream1.us-east.bsky.network/subscribe |
Jetstream endpoint |
signingKeyPath |
./state/signing.key |
secp256k1 private key (hex) |
reverifyInterval |
24h |
Re-verification frequency |
Config files support comments and trailing commas (hujson).
Testing#
go test ./...
Docker#
docker build -t atmosphere-mail-labeler .
docker run -v ./state:/app/state -p 8081:8081 atmosphere-mail-labeler
Architecture#
cmd/labeler/ Entry point, wiring, graceful shutdown
internal/
config/ hujson config loading
store/ SQLite persistence (labels, attestations, cursor)
label/signer CBOR + secp256k1 label signing, did:key derivation
label/manager Verification orchestration, label create/negate
dns/ MX, SPF, DKIM, DMARC verification (injectable resolver)
domain/ DID-to-domain control verification
server/ queryLabels (HTTP) + subscribeLabels (WebSocket)
jetstream/ Firehose consumer with collection filtering
scheduler/ Periodic re-verification
License#
MIT
Author#
Scott Lanoue (@scottlanoue.com)