Deploy Mailpit | (Just Updated) Email Testing SMTP Server with REST API, Login Preset, Data Survives Redeploys
Mailpit email testing server: SMTP inbox, web UI and REST API
mailpit
Just deployed
/data
Deploy and Host Mailpit on Railway
Built for an LLM agent to deploy and use. There is no setup page to open: the web UI and SMTP logins are created from generated passwords on first boot, and the contract below lists every address, variable name and one script that sends a message through the REST API and reads it back.
Mailpit is an open source email testing server. Your application sends mail to its SMTP port instead of a real provider, and every message lands in a web inbox and a REST API, with HTML and text bodies, headers, attachments, link checks and search. It is a single Go binary that idles at under 10 MB of memory.
About Hosting Mailpit
This template runs one service: the official axllent/mailpit v1.33.0 image, pinned by digest, with a volume on /data. The volume holds the SQLite message store, so the inbox survives redeploys. The web UI and REST API share one port and sit behind HTTP Basic auth as the user admin. The SMTP listener (port 1025) requires a login as the user mailpit. Both passwords are generated per deploy.
The SMTP port is reachable on Railway's private network only (mailpit.railway.internal:1025), which is where test mail comes from: services in the same project. It is not exposed to the internet, because Railway cannot give one service both an HTTP healthcheck and a public TCP proxy. The start command moves the web UI from Mailpit's default port 8025 to Railway's injected PORT so the healthcheck and the public domain reach it, and keeps the newest 5000 messages.
Agent contract
- Public URL:
MAILPIT_PUBLIC_URL(https://plus the service'sRAILWAY_PUBLIC_DOMAIN). The web UI is at/, the REST API under/api/v1/. - Private URLs: web and API
http://mailpit.railway.internal:8080(MAILPIT_PRIVATE_URL); SMTPmailpit.railway.internalport1025, plain text with login, ready-made asMAILPIT_SMTP_URL(smtp://mailpit:PASSWORD@mailpit.railway.internal:1025). - Credentials:
MAILPIT_UI_PASSWORD(useradmin, web UI and API) andMAILPIT_SMTP_PASSWORD(usermailpit, SMTP). - Auth: the API takes HTTP Basic auth (
curl -u admin:$MAILPIT_UI_PASSWORD). SMTP uses AUTH PLAIN or LOGIN withmailpitand the SMTP password; set the client to "no TLS" or "STARTTLS optional", since the private network is the transport. - Health:
GET /livezreturns 200 without credentials. - API:
GET /api/v1/messages,GET /api/v1/message/{id},GET /api/v1/search?query=...,POST /api/v1/send,DELETE /api/v1/messages.
# run with MAILPIT_PUBLIC_URL and MAILPIT_UI_PASSWORD set
U="$MAILPIT_PUBLIC_URL"; A="admin:$MAILPIT_UI_PASSWORD"
curl -s -o /dev/null -w "livez: %{http_code}\n" "$U/livez"
curl -s -o /dev/null -w "no auth: %{http_code}\n" "$U/api/v1/messages"
curl -s -u "$A" -H "Content-Type: application/json" \
-d '{"From":{"Email":"app@example.com"},"To":[{"Email":"user@example.com"}],"Subject":"hello from an agent","Text":"sent through the API"}' \
"$U/api/v1/send"; echo
curl -s -u "$A" "$U/api/v1/search?query=subject:hello" | sed -n 's/.*"messages_count":\([0-9]*\).*/found: \1/p'
curl -s -u "$A" -X DELETE "$U/api/v1/messages"; echo
A fresh deploy prints livez: 200, no auth: 401, a JSON object with the new message ID, found: 1, and ok for the delete.
To send over SMTP from another service in the same project, point it at MAILPIT_SMTP_URL (or host mailpit.railway.internal, port 1025, user mailpit, password MAILPIT_SMTP_PASSWORD) and read the result back with the same API calls.
Why Deploy Mailpit on Railway?
Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.
By deploying Mailpit on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.
- Agent-ready - generated logins, contract block and one working script; nothing to type into the deploy form.
- Locked from boot - the inbox and the SMTP port both need a login, so test mail with real-looking content is not public.
- State survives redeploys - the message store lives on a volume, and the image is pinned by digest.
- A healthcheck that works -
/livezpasses without credentials, so a bad deploy is caught instead of served. - One light service - no database to run alongside, under 10 MB of memory when idle.
Common Use Cases
- Staging mail catcher - point a staging app's SMTP settings at
MAILPIT_SMTP_URLand read password resets and order emails in the web UI. - End-to-end tests - a test run sends mail, then polls
/api/v1/searchfor the message and extracts the link or code. - Agent email checks - an AI agent verifies that the mail its code sends renders, has the right headers and links, and is deleted afterwards.
Dependencies for Mailpit Hosting
- One Railway volume on
/data, created by the template.
Deployment Dependencies
Implementation Details
| Variable | Purpose |
|---|---|
MAILPIT_UI_PASSWORD | Password of the admin user for the web UI and REST API. Generated per deploy. |
MAILPIT_SMTP_PASSWORD | Password of the mailpit SMTP user. Generated per deploy. |
MAILPIT_PUBLIC_URL | HTTPS address of the web UI and API. |
MAILPIT_PRIVATE_URL | Web UI and API address on the private network. |
MAILPIT_SMTP_URL | SMTP connection string on the private network, password included. |
The start command exports MP_UI_BIND_ADDR from PORT, the database path, the message limit, MP_UI_AUTH and MP_SMTP_AUTH (built from the two passwords), then runs the image's own /mailpit.
Template Content
mailpit
axllent/mailpit:v1.33.0