EmailFlare is intentionally optimized for minimum infrastructure.
The default self-host deployment uses:
- one application container
- embedded mesahub with SQLite-backed storage
- one mounted volume at
/data - Cloudflare Email Sending as the outbound delivery provider (for production)
You do not need Postgres, Redis, or a separate database service for the default setup.
- Docker with Compose support
- a Cloudflare account with Email Sending enabled (not required if using test API keys only)
- a Cloudflare API token with the required email sending permissions (not required if using test API keys only)
cp .env.example .env.localSet at least:
ADMIN_TOKEN=<openssl rand -hex 32>
SESSION_SECRET=<openssl rand -hex 32>
MESAHUB_URL=mh://local/emailflare
CF_API_TOKEN=<cloudflare token>
CF_ACCOUNT_ID=<cloudflare account id>
Notes:
MESAHUB_URL=mh://local/emailflarekeeps storage embedded and local to the deployment- data persists in the Docker volume mounted at
/data - keep
ADMIN_TOKENandSESSION_SECRETat 32+ characters
docker compose --env-file .env.local -f compose.yaml up --build -dOr with just:
just prodcurl http://localhost:8090/healthThen open:
- app:
http://localhost:8090
Note: The Mailpit UI is only available when running the dev stack (
compose.dev.yaml). It is not included in the production image.
The production compose file stores app data in the app-data Docker volume.
Back it up with standard Docker volume backup procedures or by snapshotting the host storage where Docker volumes live.
If you are running from source:
git pull
docker compose --env-file .env.local -f compose.yaml up --build -dIf you are running from the published image, pull the new tag and redeploy the container with the same mounted /data volume.
If you want to move storage out of the app container later, replace MESAHUB_URL with an external mesahub URL.
The minimum-infra recommendation remains the embedded local setup until you have a reason to split services.
For local development, use compose.dev.yaml instead of compose.yaml. It runs the same stack but adds a Mailpit container as the SMTP backend so emails are never delivered to real inboxes.
docker compose --env-file .env.local -f compose.dev.yaml up
# or:
just devOnce running:
- app:
http://localhost:8090 - Mailpit UI:
http://localhost:8090/mailpit/
You do not need CF_API_TOKEN or CF_ACCOUNT_ID set when using the dev stack with test API keys.
EmailFlare has built-in test mode that works on any deployment (local, Railway, Docker, etc.):
- Live API keys send through the Cloudflare Email Sending API
- Test API keys route sends through SMTP — no Cloudflare credentials required
To use test mode on any deployment:
- Set
SMTP_HOSTandSMTP_PORTto any SMTP catcher (Mailpit, Mailtrap, etc.) - Create a test API key from the admin UI (Keys page)
- Send using that key — emails go to your SMTP catcher, never to real recipients
Optional auth env vars:
SMTP_USER=<username>
SMTP_PASS=<password>
Leave them unset for unauthenticated SMTP (e.g. local Mailpit).