Mailpit
Videos
Overview: Mailpit on Ubuntu 24.04 on Azure: overview (watch on YouTube)
Launch and log in: Mailpit on Ubuntu 24.04 on Azure: launch and log in (watch on YouTube)
Deep Dive: Mailpit on Ubuntu 24.04 on Azure: deep dive (watch on YouTube)
Overview
Mailpit is a small, fast, self-hosted email and SMTP testing tool for developers. It runs a fake SMTP server that catches every message your application sends and stores each one. A modern web interface shows each message, where you can read the HTML, plain text and raw source, inspect headers and attachments, run HTML and link checks, and release messages onward when you choose.
Mailpit never delivers mail externally, so it is completely safe to point your development and staging applications at it. Nothing ever reaches a real inbox.
The SecureAnyCloud image installs the pinned Mailpit 1.30.3 static binary and runs it as a dedicated mailpit system user under systemd. An nginx reverse proxy fronts the web UI on port 80, configured for the WebSocket the live message list uses. The SMTP listener is exposed on port 25 for your applications, and the SQLite message store lives on a dedicated Azure data disk. A unique web UI password is generated on the first boot of every VM.
What you get:
- Mailpit 1.30.3 (single static Go binary) running as the
mailpitsystemd service - A fake SMTP server on
:25that captures every message your apps send and never delivers externally - The Mailpit web UI on
:80, fronted by nginx with the WebSocket upgrade proxied - HTTP Basic Auth protecting the web UI and REST API, with a unique password generated on first boot
- A dedicated Azure data disk at
/var/lib/mailpitholding the SQLite message store mailpit.serviceandnginx.serviceas systemd units, enabled and active- An unauthenticated
/healthzendpoint for Azure Load Balancer health probes - 24/7 SecureAnyCloud support
Prerequisites
- An active Azure subscription, an SSH key pair, and a VNet and subnet in the target region
- Standard_B2s (2 vCPU / 4 GiB RAM) as a comfortable starting point. Mailpit is very light on resources
- NSG inbound rules that allow
22/tcpfrom your management network,80/tcpfor the web UI,443/tcpif you add TLS, and25/tcpfrom the networks that run the applications under test, so they can deliver mail to Mailpit
Mailpit serves plain HTTP on port 80. If the VM is reachable beyond a trusted network, terminate TLS in front of it with your own domain (see Maintenance).
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Mailpit by SecureAnyCloud, and select Create.
On the Basics tab, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22) and HTTP (80).
Review the dedicated data disk on the Disks tab. Then choose Review + create, followed by Create. After creation, add an inbound NSG rule for SMTP (25) from your application networks.
Step 2 - Deploy from the Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:mailpit-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name mailpit \
--image sac1647283583153:mailpit-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name mailpit --port 80 --priority 1010
az vm open-port --resource-group <your-rg> --name mailpit --port 25 --priority 1020Step 3 - Connect to your VM
Connect over SSH as azureuser.
ssh azureuser@<vm-public-ip>Step 4 - Confirm the services are running
Check that both services are active.
systemctl is-active mailpit.service nginx.serviceBoth report active. Mailpit listens for SMTP on 0.0.0.0:25 and serves its web UI and REST API on the loopback connector 127.0.0.1:8025. nginx fronts the UI on port 80 with the WebSocket upgrade the live message list requires. Mailpit's SQLite message store lives on the dedicated Azure data disk mounted at /var/lib/mailpit.
Step 5 - Retrieve your web UI password
Mailpit protects its web UI and REST API with HTTP Basic Auth. The username is admin. A unique password is generated on the first boot of your VM and written to a root-only file. Read the file.
sudo cat /root/mailpit-credentials.txtThe file contains MAILPIT_USERNAME, MAILPIT_PASSWORD, the MAILPIT_URL to open in a browser and the MAILPIT_SMTP host:port your applications should send to. The password is stored on disk only as a bcrypt hash in /etc/mailpit/ui-auth, so no plaintext password ships in the image. Store the password somewhere safe.
Step 6 - Confirm the health endpoint
nginx serves an unauthenticated health endpoint for load balancers and probes. Request it.
curl -s http://localhost/healthzThe endpoint returns ok. It never requires authentication, so it is safe for an Azure Load Balancer health probe.
Step 7 - Confirm authentication and SMTP capture
A password is set on first boot, so an unauthenticated request to the web UI returns HTTP 401. Nobody reaches your captured mail without the password.
Read the per-VM password from the credentials file and prove the round trip. The unauthenticated request is rejected, and the correct password authenticates.
PW=$(sudo grep '^MAILPIT_PASSWORD=' /root/mailpit-credentials.txt | cut -d= -f2-)
echo "unauth: $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/)"
echo "authed: $(curl -s -o /dev/null -w '%{http_code}' -u admin:$PW http://127.0.0.1/)"The output is unauth: 401 followed by authed: 200. Every message your applications send to port 25 is captured and readable through the authenticated REST API at /api/v1/messages.
Step 8 - Sign in to the web UI
Browse to http://<vm-public-ip>/. When your browser prompts for a username and password, enter admin and the password from Step 5.
Mailpit opens on the inbox. It lists everything your applications have sent, newest first, with the sender, recipient, subject, size and time on each row.
Step 9 - Read a captured message
Select any message to open it. Mailpit renders the email exactly as a mail client would, with the From, To, Subject and Date headers at the top. Tabs let you switch between the HTML view, plain text, HTML source, full headers, raw MIME, and automated HTML and link checks.
Step 10 - Inspect the message source and headers
Switch to the HTML Source tab (or Headers or Raw) to see the exact markup and MIME your application produced. This is invaluable when you debug templating, encoding or deliverability issues.
Step 11 - Search the mailbox
Use the search box at the top to filter the mailbox by sender, recipient, subject or body text. This is handy when an automated test suite has generated a large number of messages.
Step 12 - Point your application's SMTP at Mailpit
Configure your application's outbound SMTP settings to use this VM on port 25. No username, no password and no TLS are required by default, which matches how most frameworks send to a local development mail catcher.
- Host: the VM's private or public IP (the
MAILPIT_SMTPvalue from Step 5) - Port: 25
- Encryption and auth: none
Every email the application then sends is captured by Mailpit and appears instantly in the web UI. Nothing is ever delivered to a real recipient, so it is safe to exercise password resets, order confirmations, notification digests and any other mail flow against production-like data.
Step 13 - Confirm data lives on the dedicated disk
Mailpit's SQLite message store is kept under /var/lib/mailpit on the dedicated Azure data disk, so your captured messages survive OS changes and the disk can be resized independently. Check the mount.
findmnt /var/lib/mailpitA separate Azure data disk backs the mount. The disk is captured into the image and re-provisioned on every VM.
Maintenance
- Password: The web UI password is set on first boot and stored as a bcrypt entry in
/etc/mailpit/ui-auth. To change it, runsudo htpasswd -B /etc/mailpit/ui-auth admin, thensudo systemctl restart mailpit. - Retention: Mailpit keeps the most recent messages and prunes automatically. Adjust retention with the
--maxoption in themailpit.serviceunit if you need a larger or smaller mailbox. - Releasing mail: To forward a captured message to a real recipient, configure a release SMTP relay in the message view's Release action.
- Upgrades: Mailpit is a single static binary at
/usr/local/bin/mailpit. To upgrade, download a newer pinned release, verify its checksum, replace the binary and runsudo systemctl restart mailpit. Your message store under/var/lib/mailpitis preserved. - Storage: All Mailpit state lives under
/var/lib/mailpiton the data disk. Back up that volume to protect your captured messages. - TLS: Mailpit serves plain HTTP on port 80. Front it with TLS (for example certbot with your own domain) before exposing it beyond a trusted network.
- Security patches: unattended-upgrades remains enabled, so the OS continues to receive security updates automatically.
Support
SecureAnyCloud provides 24/7 expert support for this image. Contact sales@secureanycloud.com.
Deploy on Azure
Launch Mailpit on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
Mailpit is a self-hosted email and SMTP testing tool for developers. It runs a fake SMTP server that catches the mail your applications send. A fast, searchable web interface shows every captured message.
Mailpit never delivers mail to real recipients, so you can safely point a development or staging environment at it and inspect exactly what your application would have sent.
What you get:
- Mailpit as a single static Go binary, running as the dedicated
mailpitsystem user under systemd - SMTP on port 25, and a web UI and REST API on the loopback interface at
127.0.0.1:8025 - nginx as a reverse proxy on port 80 (and 443 once you add TLS), with the WebSocket upgrade the live-updating message list needs already configured
- A SQLite message database on a dedicated EBS data volume mounted at
/var/lib/mailpit, independently resizable and separate from the operating system disk - A UI password unique to each instance. A one-shot service generates it on first boot, applies it to Mailpit as an htpasswd bcrypt credential, and records it in
/root/mailpit-credentials.txtwith mode 0600 - No shared or default credentials in the image. The health endpoints used by load balancers stay open, while the web UI and API require the generated password
- For each message: rendered HTML, plain text and raw source, attachments, headers, and spam and link checks
Prerequisites
Before you deploy this image, make sure you have the following.
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group allowing inbound port 22 from your management network, inbound ports 80 and 443 from the networks your operators will reach the Mailpit UI on, and inbound port 25 from the application hosts that will send test mail
- The AWS CLI (version 2) installed locally if you plan to deploy from the command line
Launch the Instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images, choose AWS Marketplace AMIs and search for Mailpit. Select the SecureAnyCloud listing and choose Select, then Continue on the subscription summary.
Pick an instance type of t3.small or larger. Choose your EC2 key pair under Key pair (login). Under Network settings, select your VPC and subnet, then create or select a security group. The group must allow inbound port 22 from your management network, inbound ports 80 and 443 from the networks your users use, and inbound port 25 from the application hosts that will send mail.
Leave the root volume at the default size or larger. The image adds a separate data volume for the message database automatically.
Select Launch instance. First-boot initialization takes under a minute after the instance state becomes Running and the status checks pass.
Launch the Instance from the AWS CLI
Launch an instance from the SecureAnyCloud Mailpit Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens ports 22, 80, 443 and 25 as described above.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type t3.small \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":30,"VolumeType":"gp3"}}]' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=mailpit-01}]'On success, the command prints a JSON document. Note the instance ID, then retrieve the public address once the instance is running with aws ec2 describe-instances --instance-ids <instance-id> --query "Reservations[].Instances[].PublicIpAddress" --output text.
Connect and Retrieve the UI Password
Connect over SSH with the key pair you selected and the public IP address from Step 2. The SSH login user depends on the operating system of the AMI variant you launched. For Mailpit 1.30 on Ubuntu 24.04, the login user is ubuntu.
The first-boot service runs before the SSH daemon becomes ready, so the credentials file is always in place when you log in for the first time.
ssh <login-user>@<public-ip>
sudo cat /root/mailpit-credentials.txtThe plain-text file contains the Mailpit URL, the username admin, and the per-instance UI password. From the same SSH session, confirm the deployment is healthy. The health endpoint is open and served by nginx.
curl -fsS http://127.0.0.1/healthzokAn ok response confirms nginx is fronting the application. Next, confirm the services that make up the stack are running, and check the Mailpit version.
systemctl is-active mailpit nginx mailpit-firstboot /usr/local/bin/mailpit versionactive active active /usr/local/bin/mailpit v1.30.3 compiled with go1.26.4 on linux/amd64Mailpit listens for SMTP on port 25 on all interfaces and serves its UI and API on the loopback interface. Confirm the listeners.
sudo ss -tlnp | grep -E ':25 |:8025 'LISTEN 0 1024 *:25 *:* users:(("mailpit",pid=1742,fd=8)) LISTEN 0 1024 127.0.0.1:8025 *:* users:(("mailpit",pid=1742,fd=9))First Sign-in
Open a web browser and navigate to http://<public-ip>/. Mailpit protects its web UI with HTTP Basic authentication, so your browser prompts for a username and password. Enter the username admin and the per-instance password from /root/mailpit-credentials.txt.
Mailpit opens on the inbox. It lists every captured message, newest first, with the sender, recipient, subject, size and time received. A search box filters the mailbox. As new mail arrives, the list updates live over the WebSocket.
Point Your Application at the SMTP Port
Configure your application's SMTP settings to send through this instance: host <public-ip>, port 25, with no authentication and no TLS required by default. Every message your application sends is then captured by Mailpit instead of being delivered to a real mail server.
Prove the capture path end to end from the instance itself. Send a test message to the SMTP port, then confirm it appears through the authenticated API. The following command sends one message with the Python standard library.
python3 -c "import smtplib; from email.message import EmailMessage; m=EmailMessage(); m['From']='app@example.com'; m['To']='inbox@example.com'; m['Subject']='Hello from my app'; m.set_content('This message was captured by Mailpit.'); s=smtplib.SMTP('127.0.0.1',25,timeout=10); s.send_message(m); s.quit(); print('sent')"sentNow read the mailbox back through Mailpit's REST API, authenticating with the per-instance password. The total field is the number of captured messages.
PW=$(sudo grep '^MAILPIT_PASSWORD=' /root/mailpit-credentials.txt | cut -d= -f2-)
curl -s -u "admin:$PW" http://127.0.0.1/api/v1/messages | jq '.total'1A non-zero count confirms the message was captured. The same message now appears at the top of the inbox in the web UI.
Inspect a Captured Message
Select any message in the inbox to open it. Mailpit shows the envelope (From, To, Subject, Date and size) above a set of tabs. The default HTML tab renders the message exactly as an email client would, so you can check layout, images and links. The Text tab shows the plain-text alternative and the Raw tab shows the complete raw source. Use the Download control to download the message or any attachment. The HTML Source, Headers, HTML Check and Link Check tabs sit alongside the others.
Read the Headers
Switch to the Headers tab to see every header on the message, with a filter box to jump to a specific one. This is where you confirm details such as Content-Type, Message-Id, Return-Path and the Received trace that Mailpit added when it accepted the message over SMTP.
Run the HTML and Link Checks
Mailpit analyzes an HTML message for email-client compatibility and for broken links. Open the HTML Check tab to see an overall support score. It also shows a breakdown across email clients and platforms such as Outlook, macOS, iOS, Android and webmail, and a list of the HTML and CSS features in the message that are only partially supported.
Open the Link Check tab to validate every link and image URL in the message. The tab reports any that fail.
Enable HTTPS with Let's Encrypt
For any deployment reachable beyond a trusted network, serve Mailpit over HTTPS. This keeps the Basic-auth credentials and the WebSocket the live message list uses from being intercepted. The image ships with nginx, which certbot can configure automatically.
The following commands assume you have a DNS record pointing your fully qualified domain name at the instance's public IP address.
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d mailpit.your-domain.example \
--non-interactive --agree-tos -m you@your-domain.example \
--redirectcertbot obtains a certificate and rewrites the nginx server block to serve HTTPS and redirect HTTP. The WebSocket upgrade headers already in the site are preserved. The certbot systemd timer renews the certificate automatically.
Scope the security group rule for port 25 to the application hosts that need to send mail, so the SMTP port is reachable only from those sources.
Change the UI Password
The UI password is stored as an htpasswd bcrypt credential in /etc/mailpit/ui-auth. To set your own password, write a new bcrypt entry for the admin user and restart Mailpit. Replace <new-password> with the password you want.
sudo htpasswd -bB /etc/mailpit/ui-auth admin '<new-password>'
sudo systemctl restart mailpitThe -B flag stores the password as a bcrypt hash, and -b takes it from the command line so the update is scriptable. Mailpit reads the file at startup, so the new password takes effect as soon as the service restarts. To have htpasswd prompt for the password interactively, omit -b and the password argument.
Backups and Maintenance
Mailpit keeps its SQLite message store under /var/lib/mailpit on the dedicated data volume. Confirm that the store sits on its own disk.
df -h /var/lib/mailpit | tail -1/dev/nvme1n1 20G 724K 19G 1% /var/lib/mailpitBecause the store is on a separate EBS volume, you can take a coordinated EBS snapshot of it for point-in-time backups. Alternatively, archive the store to object storage.
sudo systemctl stop mailpit
sudo tar czf <backup-dir>/mailpit-$(date +%F).tgz -C /var/lib mailpit
sudo systemctl start mailpitShip the archive to an Amazon S3 bucket or another object store. Mailpit runs under systemd with a restart policy. You can empty the captured mailbox at any time, either from the UI or by deleting the store while the service is stopped. Check the service state.
systemctl is-active mailpit nginxactive activeScaling and Operations
- Scale up: Increase the instance size for a busy shared inbox. Mailpit stays responsive because it stores mail in SQLite and streams new messages over the WebSocket.
- Restrict SMTP: Scope the port 25 security group rule to only the application hosts that need to send mail. Keep the UI on 80/443 behind your management network or a load balancer.
- Load balancing: Put the web tier behind an Application Load Balancer and terminate TLS there. Forward the WebSocket upgrade so the live message list connects, and use the open
/livezand/readyzendpoints for target health checks. - Storage: Grow the data volume by extending the EBS data volume and running
sudo resize2fson/var/lib/mailpit. - Testing: Wire the REST API on
/api/v1/messagesinto your automated integration tests to assert that a message was sent. Delete the message between test runs. - Versioning: Pin the Mailpit version for a fleet by controlling which AMI version you launch.
The official Mailpit documentation is available at https://mailpit.axllent.org/docs/.
Support
SecureAnyCloud provides 24/7/365 expert technical support for this image. Guaranteed response within 24 hours, one hour average for critical issues. Contact sales@secureanycloud.com.
For general Mailpit questions consult the documentation at https://mailpit.axllent.org/docs/. Mailpit is a trademark of its respective owner; use here is nominative and does not imply affiliation or endorsement.
Deploy on AWS
Launch Mailpit on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com