Application Infrastructure Azure

Mailpit on Ubuntu 24.04 on Azure User Guide

| Product: Mailpit on Ubuntu 24.04 LTS on Azure

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, stores each one, and shows it in a modern web interface 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. Because Mailpit never delivers mail externally, it is completely safe to point your development and staging applications at it: nothing ever reaches a real inbox. The cloudimg image installs the pinned Mailpit 1.30.3 static binary, runs it as a dedicated mailpit system user under systemd, and fronts its web UI on port 80 with an nginx reverse proxy configured for the WebSocket the live message list uses. The SMTP listener is exposed on port 25 for your applications, the SQLite message store lives on a dedicated Azure data disk, and a unique web UI password is generated on the first boot of every VM. Backed by 24/7 cloudimg support.

What is included:

  • Mailpit 1.30.3 (single static Go binary) running as the mailpit systemd service
  • A fake SMTP server on :25 that 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/mailpit holding the SQLite message store
  • mailpit.service + nginx.service as systemd units, enabled and active
  • An unauthenticated /healthz endpoint for Azure Load Balancer health probes
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a comfortable starting point; Mailpit is very light on resources. NSG inbound: allow 22/tcp from your management network, 80/tcp for the web UI, 443/tcp if you add TLS, and 25/tcp from the networks that run the applications under test so they can deliver mail to Mailpit. Mailpit serves plain HTTP on port 80; for production-adjacent use, 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 cloudimg, and select Create. On Basics 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). After creation, add an inbound NSG rule for SMTP (25) from your application networks. Review the dedicated data disk on the Disks tab, then Review + create -> Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name mailpit \
  --image <marketplace-image-urn> \
  --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 1020

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

systemctl is-active mailpit.service nginx.service

Both 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.

The mailpit and nginx services active, the SMTP listener on port 25, the web UI on loopback 8025 and nginx on port 80, and the dedicated 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 and a unique password is generated on the first boot of your VM and written to a root-only file:

sudo cat /root/mailpit-credentials.txt

This 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.

The Mailpit version, the per-VM credentials file with the generated admin password and URLs, and the bcrypt ui-auth entry that proves no plaintext password ships in the image

Step 6 - Confirm the health endpoint

nginx serves an unauthenticated health endpoint for load balancers and probes:

curl -s http://localhost/healthz

It returns ok. This endpoint never requires authentication, so it is safe for an Azure Load Balancer health probe.

Step 7 - Confirm authentication and SMTP capture

Because a password is set on first boot, an unauthenticated request to the web UI returns HTTP 401, so nobody reaches your captured mail without the password. The following reads the per-VM password from the credentials file and proves the round-trip - unauthenticated 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/)"

It prints unauth: 401 then authed: 200. Every message your applications send to port 25 is captured and readable through the authenticated REST API at /api/v1/messages.

The HTTP Basic Auth round-trip returning 401 unauthenticated and 200 with the per-VM password, a test email delivered to SMTP port 25, and the authenticated messages API reporting the captured mailbox count

Step 8 - Sign in to the web UI

Browse to http://<vm-public-ip>/. Your browser prompts for a username and password: enter admin and the password from Step 5. Mailpit opens on the inbox - the message list of everything your applications have sent, newest first, each row showing the sender, recipient, subject, size and time.

The Mailpit inbox message list showing captured test emails with sender, recipient, subject, size and received time

Step 9 - Read a captured message

Click 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 and tabs to switch between the HTML view, plain text, HTML source, full headers, raw MIME, and automated HTML and link checks.

A rendered HTML email in Mailpit showing the message headers and the HTML body with its call-to-action button, plus the HTML, Text, Source, Headers, Raw and HTML Check tabs

Step 10 - Inspect the message source and headers

Switch to the HTML Source tab (or Headers / Raw) to see the exact markup and MIME your application produced - invaluable when you are debugging templating, encoding or deliverability issues.

The Mailpit HTML Source tab showing the exact HTML markup of the captured message

Step 11 - Search the mailbox

Use the search box at the top to filter the mailbox by sender, recipient, subject or body text - handy when an automated test suite has generated a large number of messages.

The Mailpit search box filtering the mailbox to the messages matching a query

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_SMTP value from Step 5)
  • Port: 25
  • Encryption / 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:

findmnt /var/lib/mailpit

The mount is backed by a separate Azure data disk 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, run sudo htpasswd -B /etc/mailpit/ui-auth admin and then sudo systemctl restart mailpit.
  • Retention: Mailpit keeps the most recent messages and prunes automatically; adjust retention with the --max option in the mailpit.service unit if you need a larger or smaller mailbox.
  • Releasing mail: to actually 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 run sudo systemctl restart mailpit. Your message store under /var/lib/mailpit is preserved.
  • Storage: all Mailpit state lives under /var/lib/mailpit on 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

cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.