Skip to main content

Mail Quickstart

This brings up the whole stack — Stalwart Mail Server plus StateSet Mail — and sends a message that round-trips back to the inbox API.

1. Start Stalwart

Wait about 20 seconds, then grab the auto-generated admin password:

2. Configure Stalwart

Open http://localhost:8080 and sign in as admin with the printed password.
  • Settings → Domains — add local.test. Any domain works for local testing; mail won’t leave the box.
  • Management → Accounts — create an account agent in the local.test domain and set a password.
You now have a mailbox agent@local.test that can both send and receive locally.

3. Plug the credentials into .env

4. Start StateSet Mail

You should see outbound worker started, inbox worker starting, and listening.

5. Send a message

The outbound worker relays it through Stalwart; the IMAP worker polls it back. Read it:
Pass an Idempotency-Key header so a retried call doesn’t double-send.

Running natively

The service is a single Rust binary against one SQLite file — Docker is a convenience, not a requirement. Set the same environment variables and run it directly; DATABASE_URL defaults to sqlite://data/mail.db with WAL mode enabled.

Set up tracking

Opens, clicks, and List-Unsubscribe all need a public origin so the recipient’s mail client can reach back:
Without it, tracking and one-click unsubscribe are disabled. Every emitted /t/* URL is HMAC-signed with TRACKING_SECRET (which defaults to the first API key) — rotate it carefully, since rotation invalidates in-flight links.

Next steps

Overview

The full feature surface.

Conversations

Triage threads instead of messages.

MCP server

Wire it up to Claude.

Configuration

Every environment variable.