Self-hosting

Your mail. Your machine.

Sendtrap Community is the MIT-licensed, self-hosted email sandbox: point your application's outgoing mail at it and every message is captured, parsed, and browsable — nothing is ever delivered. It runs on your own machine or network, with no external account and no internet access required.

What you get

Community is a single-workspace edition of Sendtrap, built on the same MIT-licensed sendtrap/core package that powers the hosted Cloud (see Open source for how the pieces fit together). The capture-and-inspect engine is identical:

  • An SMTP server that catches instead of sendsphp artisan mail:smtp-server accepts SMTP (including STARTTLS) on port 1025 by default and files every message into an inbox.
  • Projects and inboxes — organise captured mail per app or environment; each inbox has its own SMTP credentials and API token.
  • A message browser — HTML/text/raw views, MIME structure, attachments, envelope and BCC capture, merge-tag detection.
  • Message checks — deliverability lint checks and HTML client compatibility scored against the caniemail dataset, fully offline from a checked-in snapshot. HTML Check has no plan gate in Community — the API surface that needs Starter+ on Cloud is simply on.
  • The full REST API — the same token-authenticated endpoints as Cloud, including wait & assert and the Mailtrap-compatible aliases. The API reference applies as-is; only the plan-gating notes don't.
  • Public share links, webhooks and auto-forwarding for individual messages.

Install (Docker)

The fastest path: one durable container carrying the web UI/API (:8080), the SMTP ingestion daemon (:1025), a queue worker and the scheduler — SQLite and all state on a single volume, nothing else to install. Images are published to GHCR and cosign-signed.

bash
ADMIN_PASSWORD="$(openssl rand -base64 15)" && echo "admin password: ${ADMIN_PASSWORD}"
docker run -d --name sendtrap \
  -p 80:8080 -p 1025:1025 \
  -e APP_URL=http://localhost \
  -e SENDTRAP_ADMIN_NAME="Admin" \
  -e SENDTRAP_ADMIN_EMAIL="admin@example.com" \
  -e SENDTRAP_ADMIN_PASSWORD="$ADMIN_PASSWORD" \
  -v sendtrap-data:/data \
  ghcr.io/sendtraphq/sendtrap-community:latest

# then see a first message straight away — no app wiring needed
docker exec sendtrap php artisan sendtrap:send-test

Open APP_URL, log in as the admin user, and the seeded test message is waiting in the starter inbox. The repository also ships a hardened reference docker-compose.yml (read-only rootfs, dropped capabilities) and an ephemeral CI profile (SENDTRAP_MODE=ci — zero-config, deterministic credentials, boots seeded in seconds for test jobs). See docker/README.md for the full runbook: build, run, backup/restore, upgrade, external MySQL/Postgres/Redis/S3 backends, and ready-to-copy CI job examples.

Requirements (from source)

The Docker path above needs only Docker. Running from source needs:

RequirementNotes
PHP 8.3+With the sqlite3 extension — SQLite is the default database, so there's no separate database server to run
ComposerInstalls PHP dependencies, including sendtrap/core
Node.js 20+ & npmBuilds the front-end assets once — nothing Node runs in production

Install (from source)

Clone, install dependencies, then let sendtrap:install do the rest — it runs the migrations, creates the single workspace, and creates the first owner user. It's idempotent: run it as many times as you like and it converges to exactly one workspace and one bootstrap owner.

bash
git clone https://github.com/sendtraphq/sendtrap-community.git
cd sendtrap-community

composer install
cp .env.example .env
php artisan key:generate

# Migrations + the single workspace + the first owner user
# (prompts for name/email/password)
php artisan sendtrap:install

npm install
npm run build

php artisan serve            # web UI on http://localhost:8000
php artisan mail:smtp-server # SMTP ingestion on port 1025

For scripted setups, sendtrap:install takes --name, --email, --password and --workspace flags; add --force to run non-interactively — it fails instead of prompting if an owner field is missing on a fresh install.

Then seed a first message with php artisan sendtrap:send-test (add --via-smtp to prove the full SMTP wire against the running daemon). When you're ready for real mail, point your application's outgoing mail at smtp://localhost:1025 using the credentials shown on the inbox's page in the UI, and watch messages appear.

Production notes

For anything beyond a laptop, treat it like any Laravel app: set APP_ENV=production and APP_DEBUG=false in .env, serve public/ behind a real web server, and run the SMTP server and queue worker under a process supervisor.

Prefer not to run it all by hand? The durable container image above packages the whole stack, and the same image carries an ephemeral, CI-oriented profile — see Sendtrap in CI for the ready-made job recipe.

Configuration

Everything is driven by .env — the shipped .env.example documents each block. The essentials:

VariableDescription
SENDTRAP_SMTP_BINDInterface the ingestion SMTP server listens on (default 0.0.0.0)
SENDTRAP_SMTP_PORTPort it listens on (default 1025). This is the server your application sends mail to — not outbound mail credentials
SENDTRAP_INSTANCE_ALLOWED_IPSOptional install-time allowlist for SMTP clients — comma-separated addresses or CIDR ranges, applied to the workspace by sendtrap:install and editable afterwards on the owner Settings page
SPAMCHECK_ENABLEDOptional external spam-check service — off by default; Community is offline-first, and the Spam tab shows a "not configured" state rather than an error

Instance limits

There are no plans in Community — instead, every cap Cloud enforces per plan is an optional per-instance limit you set yourself. All of them are unset by default.

Limit semantics — read this before setting anything. Unset (or empty) means unlimited. A configured 0 means blocked — zero allowance, never "unlimited". So SENDTRAP_FORWARDS_PER_MONTH=0 turns forwarding off entirely. Some other sandboxes document 0 as "unlimited"; Sendtrap is deliberately the opposite — never copy limit values across from elsewhere without re-checking the direction.
VariableCaps
SENDTRAP_SENDS_PER_MINUTEIngestion rate, per minute
SENDTRAP_SENDS_PER_MONTHIngestion quota, per calendar month
SENDTRAP_FORWARDS_PER_MONTHAuto-forwards, per calendar month
SENDTRAP_EMAIL_SIZE_BYTESPer-message size, in bytes
SENDTRAP_PROJECTS_LIMITNumber of projects
SENDTRAP_INBOXES_LIMITNumber of inboxes
SENDTRAP_USERS_LIMITNumber of users (the bootstrap owner is exempt)
SENDTRAP_MESSAGES_PER_INBOXMessages kept per inbox (oldest trimmed)
SENDTRAP_RETENTION_DAYSAge-based message retention, in days (pruned daily)
SENDTRAP_STORAGE_BYTESWorkspace-wide storage across all messages and attachments
SENDTRAP_API_REQUESTS_PER_MINUTEToken-authenticated API requests per minute (unset falls back to a 300/min ceiling)

Storage

Raw messages and attachments live on the local disk by default. To use S3-compatible object storage instead, fill the AWS_* keys in .env (any S3-compatible endpoint works), then either set FILESYSTEM_DISK=s3 for new mail, or migrate everything that's already there:

bash
php artisan storage:migrate-to-s3

Both the local and s3 disks are always configured (the migrate command needs both by name), so switching is a config change, not a code change.

Users & roles

There's no public registration and no social login — users are created by the installer and then by owners, on the Users page. Every user has exactly one of three roles:

RoleCan
ownerEverything — manage users, workspace settings, projects, inboxes and mail
memberManage projects, inboxes and mail — not users or workspace settings
viewerRead-only — browse messages; SMTP and API credentials are never shown

Updating

bash
git pull
composer install
php artisan migrate
npm install && npm run build

Community pins sendtrap/core with a ^0.1 constraint. On a 0.x line, breaking changes may land in minor releases (semver 0.x semantics) — read the release notes before a minor bump.

What's Cloud-only

Community deliberately leaves out the multi-tenant layer, not the product. You don't get:

  • Teams — Community is one workspace with owner/member/viewer roles; there are no separate teams to create or switch between.
  • Billing and plans — no subscriptions, no upgrade prompts; caps are the instance limits you configure.
  • Public registration and social login — users are provisioned by owners.
  • A support team — support is public docs and the issue tracker, best-effort.

Want teams, billing-backed limits that scale without ops work, and someone else running the servers? That's the hosted Cloud — see pricing.

Rather not run it yourself?

The hosted Cloud is the same engine with teams, billing and zero ops — free to start.

Create your inbox

No credit card required