MailTrain Self Hosted Email Marketing

MailTrain logoMailTrain is a self-hosted email marketing tool that is open source, written in Node.js. MailTrain is a free alternative to Sendy, a self-hosted PHP script for managing mailing lists, which must be licensed for each domain that it is hosted on (and major updates have to be paid for). Also, email gateways compatible with MailTrain include AWS SES, SparkPost, SendGrid, and MailGun, whereas Sendy is compatible with AWS SES only.

This means that MailTrain can parse the notification webhooks that are sent by all 4 of the above email delivery services, and provide detailed analytics about opens, clicks, bounces, complaints, and unsubscribes. MailTrain has a basic automation feature, where you can set up a triggered email “X” number of days after a recipient subscribes to a list, opens, or clicks an email.

MailTrain Email Marketing vs. Mautic Marketing Automation

Marketers with more sophisticated automation needs, including campaigns with decision trees (email open/click, page hit, points threshold) that lead to multiple branches (actions), or conditional campaigns, are suggested to look at Mautic, a full-featured, open source marketing automation platform. MailTrain supports email lists with contacts that are entered manually, imported by CSV, or collected through its forms, but not dynamic lists based on contact criteria.

With Mautic, you can create custom segments that have their contact membership automatically updated based on the criteria of your choice, which can include default and/or custom fields. When a contact opts in through MailTrain form, they are forever associated with the list that’s connected with that form. On the other hand, a Mautic contact can be included or excluded from multiple segments as they’re profiled through their entire customer journey.

Also, MailTrain doesn’t have tracking code that integrates with your website, and other marketing channels such as SMS and push notifications, so it’s more of a one-trick pony compared to Mautic. Overall, MailTrain is far more limited in scope compared to Mautic, although both systems can be self-hosted. MailTrain can be compared with Sendy (self-hosted) or MailChimp (SaaS), while Mautic sits in its own class as the only self-hosted alternative to HubSpot, Marketo, and Salesforce Marketing Cloud.

Where MailTrain Fits Into the Marketing Landscape

The main benefit of using MailTrain is that it’s a very lightweight software, with a low sending cost, and the ability to handle an unlimited number of lists and subscribers. While the majority of email marketing platforms such as Constant Contact, iContact, or Mailchimp have pricing tiers based on the number of contacts stored and monthly emails sent, using MailTrain frees you from these limitations.

Users of MailTrain should be comfortable with uploading & editing email templates directly with HTML, as MailTrain doesn’t ship with any templates out of the box. Once you get a template uploaded into MailTrain however, you can use the Summernote, GrapeJS, or Mosaico visual editors to customize the content, including using tokens to personalize the emails with a subscriber’s first name or company, for example.

After the initial setup, the only cost you have to pay is based on the number of emails you send (US$0.10/1,000 emails with Amazon SES) plus a nominal hosting fee for your MailTrain instance on a cloud provider such as DigitalOcean, Linode, or UpCloud (can fit on a 1GB RAM VPS).

Connecting MailTrain with a Custom SMTP Server

If you prefer to operate your own outbound mail server (with a unique IP address or range) instead of using a third-party service, MailTrain can also integrate with ZoneMTA or Postfix through stacks such as iRedMail. If using Postfix, Mailtrain can parse the local Postfix logs to mark email addresses as bounces based on the status codes emitted by the receiving mail server.

iRedMail, like its counterpart MailCow, is an open source mail server stack with webmail, IMAP/SMTP access, and Postfix mail transfer agent (MTA) rolled into one. These would typically be self-hosted on a different virtual server from MailTrain. If you also want to have a self-hosted mail server for your business, you should plan to provision an additional VPS with at least 2 GB to 4 GB RAM or more, and preferably a backup MX as well.

A custom SMTP server is ideal for senders who consistently send a large volume of mail, or whose use case does not fit within the preferred customer profile (i.e. low bounce rates < 5-10%) of the email delivery services.

For other SMTP servers, such as email delivery services not listed above, or a self-hosted SMTP server such as iRedMail, the preferred method for MailTrain to track bounces is an industry standard known as VERP (Variable Envelope Return Path). To enable VERP, you must set up a custom MX record for a bounce domain (e.g. bounces.example.com if sending from example.com). Using this option, MailTrain rewrites the return-path for each recipient to a random string at (@) the bounce domain. Based on that random string, it can identify which email addresses bounced so they can be marked as “bounces”, and not contacted again.

MailTrain Service Architecture and System Requirements

Compared to Mautic which is a PHP app that runs on a standard LAMP (or LEMP) stack, MailTrain is a Node.js app with an internal web server that listens on a high port on localhost (the default is localhost:3000). You cannot use shared hosting, including any cPanel web hosts, for deploying a Node app – only virtual or bare metal servers in the cloud are supported. The minimum requirement for MailTrain is 1 GB RAM and 1 CPU core, although you would clearly want more if you plan to process 100,000 – 2.5 million emails in a single send. As long as Redis is enabled, MailTrain supports multi-threaded email queuing & sending, so it can take advantage of multiple CPU cores. For users who are not experienced with deploying a Node.js app, we summarize the architecture below.

Node.js is a programming language with its own package manager (much like yum or apt), which brings in the dependencies (i.e. libraries) for a Node application. Except in a development environment, Node apps aren’t designed to be accessed directly on localhost. You need a web server such as Nginx to listen for HTTPS requests on a public port such as 443, and proxy pass the requests to the Node app locally.

MailTrain v2 is a rewrite of the application, initiated after late 2018, with all the features described above.

Installing the MailTrain Node.js App on Ubuntu 18.04

Here is a summary of how to deploy MailTrain on a cloud instance running Ubuntu with a Nginx reverse proxy and SSL certificate from Let’s Encrypt.

Update apt repositories and packages.

sudo apt update && apt upgrade -y

Install Node.js 10.x which is an LTS release which is currently supported with security updates.

curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install -y nodejs

Install the ImageMagick library, so that images can be resized by the server when they are uploaded thorough MailTrain’s visual editor.

sudo apt-get install -y build-essential imagemagick

Create a directory for the MailTrain node application. The /opt/ directory is for user-installed applications, so /opt/node/ makes sense.

mkdir -p /opt/node
cd /opt/node
apt install git
git clone git://github.com/Mailtrain-org/mailtrain.git
cd mailtrain

Run the npm install to get all the dependencies & required libraries for MailTrain.

npm install --production

Install MariaDB as the backend to store the database and settings for MailTrain. Run mysql_secure_installation and set a strong, secure root password.

sudo apt install mariadb
sudo systemctl enable mariadb
sudo systemctl start mariadb
mysql_secure_installation

Create the database and user for MailTrain in the MariaDB console.

mysql -uroot -p
mysql > create database mailtrain;
mysql > create user 'mailtrain'@'localhost' identified by 'secret';
mysql > grant all privileges on mailtrain.* to 'mailtrain'@'localhost';
mysql > flush privileges;
mysql > exit

Install Redis to increase the performance of MailTrain’s sending speed.

sudo apt install redis
sudo systemctl enable redis-server
sudo systemctl start redis-server

Edit & save the following lines in the default.toml config file for MailTrain.

nano /opt/node/mailtrain/config/default.toml

[www]
secret=”supersecret” # Generate a random secret to sign the session ID cookie with NEW_UUID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)

postsize=”32MB”

[mysql]
password=”secret” # the password for the ‘mailtrain’@’localhost’ user you created in the previous step
[redis]
enabled=true
[cors]
# Allow subscription widgets to be embedded
origins=['https://www.example.com']
[reports]
enabled=true

Install Nginx as a reverse proxy for MailTrain, and enable Let’s Encrypt SSL.

sudo apt install nginx
sudo systemctl enable nginx
sudo systemctl start nginx
sudo apt-get install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot python-certbot-nginx
sudo certbot certonly --webroot -w /var/www/html -d mailtrain.example.com

mkdir -p /var/www/letsencrypt
rm -f /etc/nginx/sites-available/default

sudo nano /etc/nginx/conf.d/mailtrain.conf

server {
listen 80 default_server;
server_name _;
return 301 https://$host$request_uri;
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /var/www/letsencrypt;
}
location = /.well-known/acme-challenge/ {
return 404;
}
}
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/letsencrypt/live/mailtrain.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mailtrain.example.com/privkey.pem;
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
ssl_ecdh_curve secp384r1;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}

sudo systemctl restart nginx
sudo certbot certonly --webroot -w /var/www/letsencrypt -d mailtrain.example.com

sudo nano /etc/letsencrypt/cli.ini

renew-hook = systemctl reload nginx

sudo nano /etc/crontab

15 4 * * * root certbot renew > /dev/null 2>&1

Create a Systemd service file for MailTrain to enable it at startup.

sudo nano /etc/systemd/system/mailtrain.service

[Unit]
Description=Mailtrain Server
Requires=mariadb.service
After=syslog.target network.target
[Service]
user=mailtrain
group=mailtrain
Environment="NODE_ENV=production"
WorkingDirectory=/opt/node/mailtrain
ExecStart=/usr/bin/node index.js
Type=simple
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=mailtrain
[Install]
WantedBy=multi-user.target

sudo systemctl enable mailtrain
sudo systemctl start mailtrain

Once the MailTrain instance is running, remember to sign in and change the admin password from the default username of admin and default password of test.

Also, click the dropdown in the top right corner and select Settings to update these values for your installation. Note that you should provide a real mailing address and ensure it is displayed at the bottom of each email to comply with US CAN-SPAM (and similar) regulations. This is also the page where you can input your SMTP or AWS SES credentials, in the Mailer Settings section. If using AWS SES, you need to configure a SNS topic to report bounces and complaints to https://mailtrain.example.com/webhooks/aws. If you are having trouble getting setup, we provide a professional MailTrain installation service, that includes connecting the email gateway.

  • Service Address (URL)
  • Admin Email
  • Sender name
  • Default address
  • Default “from name”
  • Default “from” email
  • Default “subject line”
  • Default homepage (URL)

MailTrain settings screenshotSet up logrotate to purge older MailTrain logs to avoid running out of disk space.

sudo nano /etc/logrotate.d/mailtrain

/var/log/mailtrain.log {
daily
rotate 12
compress
delaycompress
missingok
notifempty
copytruncate
nomail
}