Mailtrain
Overview
Mailtrain is a self-hosted newsletter and email marketing platform for building subscriber lists, designing campaigns and tracking delivery, all from your own infrastructure. It gives you list management with custom fields and segments, drag-and-drop email template editors (Mosaico and GrapesJS), subscription and unsubscription forms, regular, RSS and automation-triggered campaigns, and per-campaign reporting.
The SecureAnyCloud image ships Mailtrain 2 running on Node.js under systemd on a hardened Ubuntu 24.04 LTS base that is patched at build time, fronted by nginx. A bundled local MariaDB database and a Redis session cache make the appliance complete and useful on its own.
Mailtrain runs three separate web endpoints, all served through nginx: a trusted admin interface on port 80, a sandbox endpoint on port 8003 for the template editors, and a public endpoint on port 8004 for subscription forms and the campaign archive. The bundled MariaDB and Redis listen only on the loopback interface and are never exposed. A unique administrator password and API access token are generated on the first boot of every VM.
What you get:
- Mailtrain 2 running on Node.js 14 under systemd (
mailtrain.service), fronted by nginx - A bundled MariaDB server holding the Mailtrain database, already installed, migrated and ready
- A bundled Redis session cache
- Three nginx-fronted endpoints: trusted admin UI on
:80, sandbox editors on:8003, public subscription and archive on:8004 - A per-VM administrator password and REST API access token, generated on first boot and recorded in a root-only file
- No shipped default login: the default
admin/testaccount of Mailtrain is replaced with a unique per-VM secret, and no known or blank credential authenticates - MariaDB and Redis bound to
127.0.0.1only, never exposed to the network - Two example subscriber lists so the interface is ready to explore
- An unauthenticated
/healthzendpoint for Azure Load Balancer health probes - 24/7 SecureAnyCloud support
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.
Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting point. Choose a larger size for bigger lists and higher send volumes.
Configure the NSG inbound rules to allow 22/tcp from your management network, and 80/tcp, 8003/tcp and 8004/tcp for the three Mailtrain endpoints. Mailtrain serves plain HTTP, so for production, terminate TLS in front of it with your own domain. The bundled MariaDB and Redis are never exposed. They listen on 127.0.0.1 only.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Mailtrain 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).
Select Review + create, then Create. After creation, also open ports 8003 and 8004 (Step 2) so that the sandbox and public endpoints are reachable.
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:mailtrain-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name mailtrain \
--image sac1647283583153:mailtrain-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku StandardOpen the three Mailtrain endpoints:
az vm open-port --resource-group <your-rg> --name mailtrain --port 80 --priority 900
az vm open-port --resource-group <your-rg> --name mailtrain --port 8003 --priority 910
az vm open-port --resource-group <your-rg> --name mailtrain --port 8004 --priority 920Step 3 - Confirm the services are running
SSH in as azureuser and confirm that Mailtrain, nginx, MariaDB and Redis are all active. nginx serves the three endpoints on ports 80, 8003 and 8004, while MariaDB and Redis stay on the loopback interface.
systemctl is-active mailtrain nginx mariadb redis-server mailtrain-firstbootsudo ss -tlnp | grep -E ':80 |:8003 |:8004 |:3306 |:6379 ' | sed 's/ */ /g'Step 4 - Retrieve the per-VM administrator password
Every VM generates its own Mailtrain administrator password and REST API access token on first boot. It writes them, along with the login user and the three endpoint URLs, to a root-only credentials file. Read the file with sudo:
sudo cat /root/mailtrain-credentials.txtSign in to the admin UI as user admin with the MAILTRAIN_ADMIN_PASSWORD from this file. The MAILTRAIN_ACCESS_TOKEN authenticates the REST API.
Step 5 - Sign in to the admin interface
Browse to http://<vm-public-ip>/. The Mailtrain sign-in page opens. Enter the username admin and the password from Step 4, then click Sign in.
Step 6 - Manage subscriber lists
After you sign in, the Lists page opens. The image ships with two example lists so that you can explore straight away. Each row shows the list name, its identifier, the subscriber count and the namespace.
Use Create List to add your own list. Use the row actions to manage subscribers, fields, segments, forms and imports.
Step 7 - Manage subscribers
Open a list to reach its Subscribers view. There you can add subscribers, import them from CSV, search and segment them, and export them. The example list below is populated so that you can see the layout, the per-subscriber status and the sub-navigation for Fields, Segments, Imports and Triggers.
Step 8 - Build a campaign
Open Campaigns, then select Create Campaign to build a regular newsletter. Give it a name, choose the list or segment to send to, and pick or design a template with the Mosaico or GrapesJS editors. The campaign builder is shown below.
Step 9 - Connect a send configuration to send email
Mailtrain manages your lists, templates and campaigns out of the box. It sends email through a Send Configuration that you point at your own mail service.
Open Administration, then Send Configurations, and add one for your SMTP relay or Amazon SES account (host, port, username and password). Once a send configuration exists, you can send test messages and launch campaigns.
This keeps deliverability under your control and lets you use your own authenticated sending domain (SPF, DKIM and DMARC).
Step 10 - No known or default credentials
Mailtrain normally ships a default admin / test account. The SecureAnyCloud image removes it. The administrator password is rotated to a unique per-VM secret on first boot, and no known or blank credential authenticates.
You can verify this with the built-in round-trip check. It confirms that the per-VM API access token authenticates over HTTP while a missing or wrong token is rejected. It also confirms that the rotated administrator password rejects the default test password and other weak guesses:
sudo mariadb -N -e "SELECT CONCAT(username,' (admin account present)') FROM mailtrain.users WHERE username='admin'"sudo bash /usr/local/sbin/mailtrain-cred-roundtrip.shStep 11 - Verify the stack and where your data lives
Confirm the Node.js and Mailtrain versions, the installed schema, the example lists, and that the built-in ZoneMTA is disabled so that no MongoDB is required. The Mailtrain database lives in the bundled MariaDB. The Redis session cache and MariaDB both stay on the loopback interface, so all of your data is kept on the VM and off the network:
printf 'node %s | Mailtrain %s\n' "$(/opt/node/bin/node -v)" "$(/opt/node/bin/node -e "console.log(require('/opt/mailtrain/server/package.json').version)")"sudo mariadb -N -e "SELECT CONCAT('schema tables: ', COUNT(*)) FROM information_schema.tables WHERE table_schema='mailtrain'; SELECT CONCAT(name, ' -> ', subscribers, ' subscribers') FROM mailtrain.lists ORDER BY id"curl -sI http://127.0.0.1/healthz | head -1The three Mailtrain endpoints
Mailtrain deliberately separates its interfaces so that untrusted content (subscriber-submitted data and template previews) is served from a different origin than the admin UI:
- Trusted (
http://<vm-public-ip>/, port 80): the admin interface where you manage lists, campaigns, templates and settings. - Sandbox (
http://<vm-public-ip>:8003/, port 8003): serves the Mosaico and GrapesJS template editors in an isolated origin. - Public (
http://<vm-public-ip>:8004/, port 8004): serves subscription and unsubscription forms and the campaign archive to your recipients.
First boot sets all three to the public IP of your VM automatically. Make sure that ports 80, 8003 and 8004 are open in your NSG.
Adding your own domain and TLS
The appliance serves plain HTTP, and Mailtrain bakes its endpoint URLs into the emails and forms it serves. For production, front it with your own domain and TLS.
Terminate TLS with Azure Application Gateway, an nginx or Caddy reverse proxy, or a managed load balancer with a certificate for your domain. Then update the trustedUrlBase, sandboxUrlBase and publicUrlBase values in /opt/mailtrain/server/config/production.yaml to your public addresses, and restart Mailtrain:
sudo systemctl restart mailtrainSecurity notes
- Mailtrain serves plain HTTP. For anything beyond a trusted network, put it behind your own TLS-terminating reverse proxy or an Azure Application Gateway with a certificate for your domain.
- The bundled MariaDB and Redis listen on
127.0.0.1only and are never reachable from the network. Administer the database over SSH withsudo mariadb. - The administrator password and API access token are unique per VM, and no known or blank credential authenticates. Keep
/root/mailtrain-credentials.txtprotected, and change the password from within Mailtrain if you share access. - Restrict inbound
80/tcp,8003/tcpand8004/tcpin your NSG to the networks that need them.
Support
SecureAnyCloud maintains this image and provides 24/7 support. If you need help deploying or operating Mailtrain on Azure, contact us at secureanycloud.com.
Deploy on Azure
Launch Mailtrain 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