smtp4dev on AWS User Guide
Overview
This image runs smtp4dev, a fake SMTP server for development and testing. smtp4dev accepts the mail your applications send, stores it locally, and presents every captured message in a modern web UI inbox instead of delivering it to real recipients. Because smtp4dev never delivers mail externally, you can safely point a development, test or staging environment straight at it and inspect exactly what your application would have sent: rendered HTML, plain text and raw source, attachments, every header, and smtp4dev's HTML compatibility analysis.
smtp4dev is an ASP.NET Core application that runs as the dedicated smtp4dev system user under systemd. It accepts SMTP on port 25 and IMAP on port 143, and serves its web UI and REST API on the loopback interface at 127.0.0.1:5000, fronted by nginx as a reverse proxy on port 80 (and 443 once you add TLS), with the WebSocket upgrade its live-updating message list needs already configured. The .NET runtime is installed from the operating system's own package archive, so routine system updates keep the runtime patched rather than freezing it inside the application bundle. Every captured message is stored in a SQLite database on a dedicated EBS data volume mounted at /var/lib/smtp4dev, independently resizable and separate from the operating system disk.
On the first boot of every deployed instance, a one-shot service generates a web password unique to that instance, writes it into an override configuration file that enables HTTP basic authentication for both the web UI and the REST API, and records it in /root/smtp4dev-credentials.txt with mode 0600. Before it records anything it proves the result: it confirms that an unauthenticated request is refused, that a wrong password is refused, and that the newly generated password is accepted, both directly and through the reverse proxy. No shared or default credentials ship in the image, and the health endpoint used by load balancers stays open while the web UI and API require the generated password.
Connecting to your instance
Connect over SSH as the default login user for your operating system variant. This listing currently ships the following variant:
| OS variant | SSH login user |
|---|---|
| Ubuntu 24.04 LTS | ubuntu |
Prerequisites
Before you deploy this image you need:
- 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 smtp4dev UI on, inbound port 25 from the application hosts that will send test mail, and inbound port 143 if you want to browse captured mail over IMAP
- The AWS CLI (version 2) installed locally if you plan to deploy from the command line
Step 1: 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 smtp4dev. Select the cloudimg listing and choose Select, then Continue on the subscription summary.
Choose an instance type (the listing recommends m5.large), select your key pair, and configure a security group as described in the prerequisites. Leave the storage at the defaults: the AMI carries a dedicated data volume for the captured-mail database in addition to the operating system disk. Choose Launch instance.
Step 2: Launch the Instance from the AWS CLI
To deploy from the command line, first find the AMI ID for the listing in your Region, then launch it. Replace the placeholder values with your own.
aws ec2 run-instances \
--image-id ami-xxxxxxxxxxxxxxxxx \
--instance-type m5.large \
--key-name your-key-pair \
--security-group-ids sg-xxxxxxxxxxxxxxxxx \
--subnet-id subnet-xxxxxxxxxxxxxxxxx \
--metadata-options 'HttpTokens=required,HttpEndpoint=enabled' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=smtp4dev}]' \
--region us-east-1
The instance metadata options request IMDSv2 (HttpTokens=required); the first-boot service uses IMDSv2 to discover the instance's public IP address for the credentials file.
Step 3: Connect and Retrieve the Web Password
Once the instance has finished its first boot, connect over SSH as the login user for your variant (for the Ubuntu 24.04 variant this is ubuntu) and read the generated credentials file:
ssh -i your-key.pem ubuntu@<public-ip>
sudo cat /root/smtp4dev-credentials.txt
The file contains the web URL, the admin username, the per-instance password, and the SMTP and IMAP endpoints:
SMTP4DEV_URL=http://<public-ip>/
SMTP4DEV_USERNAME=admin
SMTP4DEV_PASSWORD=<generated-password>
SMTP4DEV_SMTP=<public-ip>:25
SMTP4DEV_IMAP=<public-ip>:143
You can confirm the stack is healthy from the shell. The service and reverse proxy should both be active, and the health endpoint answers without authentication while the UI itself returns 401 until you sign in:
systemctl status smtp4dev nginx --no-pager
curl -s http://127.0.0.1/healthz # -> ok
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/ # -> 401
You can also confirm the listeners: smtp4dev serves the web UI on loopback 127.0.0.1:5000, accepts SMTP on 0.0.0.0:25 and IMAP on *:143, and nginx listens on port 80:
sudo ss -tlnp | grep -E ':25|:80|:143|:5000'
Step 4: First Sign-in
Open the web URL from the credentials file in your browser (http://<public-ip>/). The browser prompts for HTTP basic authentication. Sign in with the username admin and the generated password. The message list loads and updates live as new mail arrives, because nginx proxies the WebSocket connection smtp4dev uses to push new messages to the browser.
Step 5: Point Your Application at the SMTP Port
Point your application's outbound SMTP settings at the instance on port 25. smtp4dev accepts mail without authentication or TLS by default, matching the way a development mail sink is used, so no credentials are needed for the SMTP side:
- SMTP host:
<public-ip> - SMTP port:
25 - Authentication: none
- TLS: none required
Every message your application sends is captured by smtp4dev and never forwarded to a real recipient. To confirm capture from the shell you can send a test message and watch it appear through the authenticated REST API:
swaks --to test@example.com --from app@example.com \
--server <public-ip>:25 --header "Subject: hello from my app"
PW=$(sudo grep '^SMTP4DEV_PASSWORD=' /root/smtp4dev-credentials.txt | cut -d= -f2-)
curl -s -u "admin:$PW" http://127.0.0.1/api/Messages \
| python3 -c 'import sys,json;print("messages:",json.load(sys.stdin)["rowCount"])'
Step 6: Inspect a Captured Message
Select any message in the list to open it. The View tab renders the HTML part exactly as a mail client would show it, so you can see the message as your recipients would.

The Parts tab lets you download attachments and inspect each MIME part, and the Source tab shows the complete raw message exactly as it was received on the wire.
Step 7: Read the Headers
The Headers tab lists every header on the captured message, including Date, From, To, Subject, Message-Id and the sending mailer, which is invaluable when you are debugging addressing, threading or deliverability metadata.

Step 8: Run the HTML Compatibility Check
The Analysis tab scores a captured HTML message for email-client support and flags each HTML or CSS feature that is only partially supported, naming the specific clients affected. This is the fastest way to catch rendering problems before a template ships.

Step 9: Browse Captured Mail Over IMAP
Because smtp4dev also speaks IMAP, you can browse the captured mailbox from any standard mail client instead of, or in addition to, the web UI. Point your mail client at the instance on port 143 and sign in with the same admin username and per-instance password:
- IMAP host:
<public-ip> - IMAP port:
143 - Username:
admin - Password: the per-instance password from the credentials file
Step 10: Review the Server Settings
The settings dialog (the gear icon in the top bar) shows the running server configuration. Note that Require Authentication (web, API) is enabled, which is what protects the web UI and REST API with the per-instance password, while SMTP intake is deliberately left open so applications under test can send without credentials.

Step 11: Enable HTTPS with Let's Encrypt
To serve the web UI over HTTPS, point a DNS name at the instance, open port 443 in the security group, and install a certificate with certbot. On the Ubuntu variant:
sudo apt-get update
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-smtp4dev-host.example.com
certbot obtains a certificate, edits the nginx site to serve TLS on port 443, and sets up automatic renewal. The reverse proxy configuration that fronts smtp4dev, including the WebSocket upgrade, is preserved.
Step 12: Change the Web Password
The per-instance password lives in the override configuration file on the data volume. To change it, edit the Password value for the admin user and restart smtp4dev:
sudo nano /var/lib/smtp4dev/appsettings.json
sudo systemctl restart smtp4dev
The relevant section looks like this:
{
"ServerOptions": {
"WebAuthenticationRequired": true,
"Users": [
{ "Username": "admin", "Password": "your-new-password" }
]
}
}
Step 13: Backups and Maintenance
The captured-mail database and the per-instance override configuration both live under /var/lib/smtp4dev on the dedicated data volume. To back up the captured mail, stop the service, copy the data directory, and start it again:
sudo systemctl stop smtp4dev
sudo tar czf /tmp/smtp4dev-backup.tgz -C /var/lib/smtp4dev .
sudo systemctl start smtp4dev
Because the data volume is a separate EBS volume, you can also take an EBS snapshot of it for point-in-time backups, or grow it independently of the operating system disk if you keep a large volume of captured mail. Routine operating system updates keep both the ASP.NET Core runtime and nginx patched, since both are installed from the distribution's package archive.
Step 14: Scaling and Operations
smtp4dev is a single-instance mail sink; it is intended to be pointed at by your development, test and staging environments rather than run as a highly available cluster. For a shared team instance, place it behind a load balancer that health-checks the unauthenticated /healthz endpoint, and keep the web UI and IMAP ports reachable only from your operators' networks. The number of messages and sessions smtp4dev retains is bounded, so the SQLite store stays small; increase the retention limits in the settings dialog if you need a deeper history.
Support
This image is provided by cloudimg with 24/7 technical support by email and chat. We can help with deployment, HTTPS and reverse-proxy configuration, SMTP and IMAP integration, storage and upgrade planning. Contact support@cloudimg.co.uk.
All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.