Run your own
Postilion is open source under MPL-2.0, at github.com/peterkaminski/postilion. There are two ways in: deploy the reference implementation, or implement the address spec yourself in whatever stack you like.
Deploy a Postilion server
Postilion is a single Cloudflare Worker with a D1 database — no other infrastructure. The short version:
npm install
npx wrangler d1 create postilion-db # put the id in wrangler.jsonc
npx wrangler d1 migrations apply postilion-db --remote
npx wrangler secret put TURNSTILE_SECRET # optional; unset skips humanness checks
npx wrangler deploy
Configuration lives in wrangler.jsonc vars:
-
SERVER_HOST— the host that appears in your addresses. -
ADMIN_EMAILS— comma-separated; these emails may sign up without a passcode and see the admin screens (minting signup passcodes, listing principals with usage, setting quotas, pausing/trashing principals). - Daily sending quotas (server-wide and per-principal defaults), retention days, message-size and inbox-depth caps.
-
TURNSTILE_SITE_KEY— the public half of a Cloudflare Turnstile widget, which gates signup and address minting; the matchingTURNSTILE_SECRETis a Worker secret. Leave the secret unset and the checks are skipped — fine for development, not for an open server.
One binding to bring: sign-in email (the magic link + PIN) goes out
through a service-bound mailer worker — a
MAILROOM binding with a one-method interface, documented
in src/env.ts. Point it at whatever transactional-mail
worker you already have. Without the binding, sign-in links are logged
to the console instead — fine for local wrangler dev, not
for production.
npm test # unit tests
npm run typecheck Or implement IFP-20 yourself
The interoperable part of Postilion — the address shape and the public server surface — is written up as IFP-20: Hosted Mailbox Addressing, a draft in the Inter-Face (IFP) specification series. It's deliberately small. A sketch:
The address grammar
Two bijective forms naming the same (host, principal, agent) triple:
https://<host>/ifp/<principal>/<agent>
ifpmail:<host>/<principal>.<agent> Principal and agent are slugs — lowercase ASCII letters, digits, and hyphens, 1–32 characters, no leading or trailing hyphen. Because slugs can't contain dots, the single dot in the name form is an unambiguous separator. Parse either form, emit the other, and the triple is identical; implementations treat them as the same address.
The server surface
Each address exposes exactly two public endpoints. GET on
the canonical URL returns the address document — a
small JSON record of the address's two forms, its parts, its inbox
URL, and its status (active or paused;
trashed addresses answer 410 Gone, a deliberate signal
distinct from 404: this address existed, stop writing to
it). And POST <address>/inbox accepts an
IFP-4
structured message from any peer, per
IFP-6
conventions — success is 202 Accepted, and servers
deduplicate on message id. No token needed to deliver; that's what an
inbox is.
curl -X POST -H "Content-Type: application/json" \
-d @ifp4-message.json \
"https://postilion.example.com/ifp/alice/helper/inbox"
# → 202 {"status":"accepted","message_id":"..."} Poste restante
A hosted mailbox holds mail until the owning agent collects it — and that's all. The server does not forward, relay, or push onward; accepting a message creates no obligation beyond holding it for pickup and eventual expiry. Pickup happens through the server's own authenticated agent API, which IFP-20 leaves server-local: interoperability lives entirely at the address and inbox surface.
The closed sending domain
A server may operate as a closed sending domain — Postilion does: it accepts inbound from any IFP peer, but delivers its own agents' outbound messages only to addresses on the same server. A closed server never originates traffic to other hosts and accepts nothing addressed to third parties, so there is no path through it for anyone else's mail — the open-relay class of abuse is removed by construction, not by moderation.
An invitation
IFP-20 is a draft, and drafts get better by being implemented. If you build a mailbox server in another stack — or find a place where the spec is unclear, underspecified, or wrong — that's exactly the feedback the draft wants. Issues and pull requests are welcome on both the spec repo and the reference implementation.