Local Setup
Prerequisites
- Rust 1.90+ —
rustup update - Docker — for Postgres and LocalStack
- sqlx-cli —
cargo install sqlx-cli --no-default-features --features postgres
1. Start Services
make up # starts Postgres (port 5433) + LocalStack (port 4566)
make db-migrate # runs SQLx migrationsThis starts two containers via docker-compose.yml:
| Service | Container | Port | Provides |
|---|---|---|---|
| Postgres 16 | mailman-postgres | 5433 | Database |
| LocalStack | mailman-localstack | 4566 | S3, SQS, SES |
TIP
make up is idempotent — it creates containers on first run, or no-ops if already running. Postgres uses port 5433 to avoid conflicts with any system Postgres on 5432.
LocalStack resources (S3 buckets, SQS queues, SES identity) are created automatically on first start by localstack/init-aws.sh.
Other commands:
make down # stop all services
make db-status # show service status
make db-reset # drop + recreate database + re-migrate2. Create .env
cp .env.example .envThe default .env points the AWS SDK at LocalStack and configures SQS queue URLs. See .env.example for all available settings.
3. Run the API
cargo run --bin mailman-bin-apiThe API is now at http://localhost:8080. Verify:
curl http://localhost:8080/health
# → {"status":"ok"}4. Run the Worker
With LocalStack running and .env configured, the worker connects to local SQS/S3/SES:
cargo run --bin mailman-bin-workerNOTE
Most API development doesn't need the worker running. It processes inbound email, outbound delivery, telemetry, and webhooks.
Running Tests
| Command | What it runs | Dependencies |
|---|---|---|
make test | Unit + integration tests | Postgres + LocalStack (started automatically) |
make test-e2e | Black-box HTTP against running API | Compose stack |
make test-all | Everything | Compose stack |
# Unit + integration tests (default — used by `make check`)
make test
# E2E tests (black-box HTTP against running API)
make test-e2e
# All tests
make test-all
# Run all CI checks (fmt, clippy, test, sqlx-check)
make check
# See all available targets
makeDocker Build
# API image
docker build --target api -t mailman-api .
# Worker image
docker build --target worker -t mailman-worker .
# Run API container locally
docker run -p 8080:8080 \
-e MAILMAN_DATABASE__URL=postgres://postgres:mailman@host.docker.internal:5433/mailman \
mailman-apiThe Dockerfile uses a multi-stage build with cargo-chef for dependency caching and distroless runtime images.