Mailchimp OpenSource Alternative: Listmonk - How to setup
Popular newsletter services like Mailchimp are now charging lots of money for sending emails, and people are –understandably so– looking for free alternatives, and I found out Listmonk to be the best free newsletter service out there.
Listmonk is a free, open source and self-hosted newsletter & mailing list manager.
Essentially, it’s free software you can use to manage and publish your newsletter and send transactional emails to your users. It works, it’s beautiful, and it’s powerful.
Listmonk main dashboard
You can try a live Listmonk demo here.
Listmonk is an ideal free alternative to Mailchimp – but it’s self-hosted, meaning you need your own server and need to follow a few technical steps to get it up and running. But once you do, you can run your email marketing for cheap or free, no matter the size of your newsletter. You will only pay at-cost for the amount of emails you send using a mailing service like Postmark or AWS SES (roughly, $1 for every 10k emails)
(Note: I’m not affiliated to Listmonk in any way. This post is not paid promotion. I just found about Listmonk while searching for free email newsletter services, and fell in love with it.)
Let’s set up a fully-functional, production-ready Listmonk instance:
Get a server
Any VPS running Ubuntu Server will do. I recommend using Hetzner or Digital Ocean. The cheapest, most basic instance will do. You can run this on something as low as 500Mb RAM, 1vCPU.
Another popular option is AWS Lightsail. AWS Lightsail offers cheap servers (instances) for as low as $3.5/mo. They have a few more locations than Hetzner or Digital Ocean, and the account creation process is slightly faster and simpler, so we’ll use that – but again, any server running Ubuntu Server 22.04 LTS will do.
To start, head to AWS Lightsail. Click on “Create instance” and choose a Linux/Unix machine. Select “Operating System (OS) only”. Select Ubuntu 22.04 LTS.
Pick a plan (the $3.5/mo or $5/mo should be enough) and hit “Create instance”.
Make sure to review your instance details so it runs in the region / location you want (rule of thumb: keep your servers closest to where the majority of your users are), and make sure it uses the correct SSH key pair so you can log into the machine.
Attach a public static IP address to your instance
By default, your AWS Lightsail instance comes with a dynamic IP address. This means every time your server gets rebooted it will pick up a new IP address. This is not ideal, as you’ll always need to type a different IP address if you want to connect to your instance.
Click on your new instance and you’ll get to the instance management page. Navigate to the “Networking” tab and click on “Attach static IP” under its Public IP address box. Follow the steps to attach the static IP. At the end, you’ll see how your instance’s IP address has been fixed to the new static IP address. This IP will now remain unchanged no matter how many times you reboot your server.
Allow HTTPS traffic to your instance
We’ll be installing an SSL certificate and accessing our Listmonk installation via HTTPS. To do that, we need to add a firewall rule on our Lightsail instance so it accepts HTTPS traffic.
Head to the “Networking” tab of your instance, and under “IPv4 Firewall”, click “Add rule”. In the Application field, choose “HTTPS” and click “Create”. The instance will now allow HTTPS traffic.
Connect via ssh to your instance
Let’s
ssh
into your instance so we can start messing around.The default user for Ubuntu Server instances is
ubuntu
, so let’s log in as that:ssh ubuntu@your-static-public-ip
Make sure to replace
your-static-public-ip
with the IP you’ve just created and make sure you’re using the same SSH key pair you used while launching the instance – and you should be in!Set up the server to run Docker containers in production
I’ve created a shell script that takes a fresh Ubuntu Server image and makes it into a production-ready machine to run Docker containers securely. It hardens the security of the machine and follows best practices to run containers in production with real internet traffic.
Note: you shouldn’t just run random scripts that random people you don’t know (like me) have posted on the internet: it’s a good practice to always examine them (here) – one trick is to run them by an LLM like ChatGPT or Claude to quickly check if they’re safe to run or not, if you’re not really sure of what they do.
To run it, just run the following commands:
wget
https://gist.githubusercontent.com/rameerez/f92ada0c83c2ecf9654cbadbc6adbbca/raw/21e74ad93740df363f344a3c40ca54a59a9b5168/docker-host-production-setup-ubuntu-server.sh
chmod +x ./
docker-host-production-setup-ubuntu-server.sh
sudo ./
docker-host-production-setup-ubuntu-server.sh
After running, it should show you a successful message:
Configure your DNS to link your domain to your instance so we can install Listmonk
Our instance is now represented by just an IP. Sure, we could connect to Listmonk using the IP alone, but since we’re configuring this for production, and we’ll be adding an SSL certificate to make everything secure – we need to link our instance to a domain name or subdomain.
Head to your DNS server settings (I’m using Cloudflare) and point a subdomain (usually something like
newsletter.example.com
) to your instance’s IP address using an A record.The exact steps will vary depending on what service you’re using for DNS (Cloudflare, Namecheap, Name.com, etc.), but it will look something like this. Save and exit.
Install Listmonk
I’ve also created another handy script to install Listmonk using Docker to our freshly configured Ubuntu Server instance. Just run it:
wget
https://gist.githubusercontent.com/rameerez/6bf916df597f0e663fbb21816c8a1b90/raw/93180f406218c902583c6b4b97dd0942c84b6dcf/listmonk-setup.sh
chmod +x ./
listmonk-setup.sh
sudo ./
listmonk-setup.sh
It will ask you for the domain where you want to install Listmonk. This is the domain or subdomain we’ve configured in the previous step, let’s assume it’s
newsletter.mydomain.com
Write your domain when the script asks for it and press enter. The script will then start installing Listmonk in the machine.
Follow the steps you will see on screen and Listmonk should be installed:
Access the Listmonk web interface
Open your favorite web browser and head to your domain
newsletter.mydomain.com
You should see the Listmonk login screen. If you click “Login”, a popup will ask for your credentials.
Your Listmonk credentials were shown in the last few messages after running the Listmonk installation script (see the step above), but if you’ve missed it, they can always be found and changed in the
config.toml
file under/opt/listmonk/config.toml
Enter your credentials and you should be logged in to the Listmonk admin dashboard
Configure Listmonk basics
Log in to Listmonk, navigate to the Settings panel and set up the newsletter general info.
In particular, make sure to set up the Root URL to
https://`newsletter.mydomain.com`
or your links and all email tracking will be broken (make sure to include thehttps://
)Make sure to change the default ‘from’ email too, and set it to an address under the domain where you intend to send mails from.
Since you’re at it, also set up the public appearance of your newsletter by providing a newsletter name and logo your users will see on public pages like signup forms, archive and unsubscribe page.
Create SMTP credentials to send emails using AWS SES
Amazon Simple Email Service (SES) is an Amazon AWS service that allows you to send email using Amazon AWS’s email servers. This is important because email servers need to have a good reputation to be able to actually deliver emails, and using your own server as your email server will probably not work.
You can also use Mailgun, Mailjet, Sendgrid or Postmark to send emails, but since we’re already using Amazon for Lightsail, we’ll just use SES.
It’s quite cheap: you’ll pay $1 for every 10k emails you send ($10 for 100k emails; $100 for 1M emails, etc.)
Head to AWS SES, select the region from which you want to send emails and follow the steps to create an identity. A verified identity is a domain, subdomain, or email address you use to send email through Amazon SES. Identity type would be “Domain”, and this would be mail.example.com
in our example.
In “Advanced DKIM settings”, select “Easy DKIM” and follow their steps to set up the right DNS records. It might be a bit cumbersome, but it’s pretty straightforward.
Once you’re done setting up your domain in AWS SES, head to the AWS SES left panel, where it says “SMTP settings”, and click the button “Create SMTP credentials”.
Follow the steps and you’ll get your SMTP Security Credentials. Don’t close this page, as you’ll need to copy these credentials in a second.
- Configure Listmonk to send email through AWS SES
Now, back in Listmonk, head to the “SMTP” tab in Settings to configure AWS SES.
Click on “Amazon SES” as indicated below, so the necessary fields get pre-filled.
Modify the “Host” with your AWS SES region (mine is us-east-1
, you can see it in your AWS url, like: https://**us-east-1.**console.aws.amazon.com
)
And paste the username and password from the AWS SES Credentials page.
Make sure to use port 2465
for SMTP. The default port for SMTP is 465, but some server providers like Hetzner simply block port 465 on their whole network to prevent email spam and email abuse; and AWS SES accepts SMTP on port 2465, so let’s just use that.
Click “Test Connection” and everything should work just fine!
- Increase your AWS SES sending quota
If you’re using this in a production setting (that is, you’ll be actually sending hundreds or thousands of emails), you’ll probably want to ask AWS to raise your SES sending quota.
By default, you can only send 200 emails per day on SES. This can be raised for free after AWS examines your case and authorizes you to send more emails (they do this to prevent spam).
You need to follow these steps to use their Service Quotas Console to open a case and explain your request. They’ll demand to know a few details about the content and nature of your emails and how you’re collecting addresses and users’ consent to be messaged.
- [Optional] Configure Listmonk to store attachments in AWS S3
Attatchments can be stored in the same server you’re running Listmonk on, but we can do better. Let’s store them on AWS S3 for better availability, replication and to avoid overloading our Listmonk server.
Amazon Simple Storage Service (S3) is an AWS service that allows you to store files. It’s kind of like Dropbox: you have “folders” (buckets), you upload files to them and they are stored in the AWS cloud so you can access them from anywhere. Some of these buckets can be public, so anyone in the world can access the files you upload (ideal for storing things like images in your newsletter attachments).
Head to AWS S3 and create a new bucket. Set “ACLs enabled” with “Bucket owner preferred” and disable the “Block all public access” checkbox.
Now, we need a different AWS user for the Listmonk app to access our S3 bucket. We’ll only grant this new user programmatic access via an access key, and we’ll create a strict policy so it only can access the S3 bucket we’ve just created.
Head to AWS IAM, and create a new user. Name it something like listmonk-s3
. Do not “Provide user access to the AWS Management Console”. In permissions, click “Attach policies directly” and click on the “Create policy” button.
Instead of using the Visual Editor, you can just copy and paste the JSON policy I’ve just created for this purpose. Make sure to edit it and replace listmonk-bucket
to the exact name you’ve given to your S3 bucket.
Create the policy, attach it to your new user, finish creating the user and open their user page in IAM. Navigate to their “Security credentials” tab, scroll down a bit to where it says “Access keys” and create a new access key for the user. Select “Application running outside AWS” and hit next until you can create and get your access key.
Once you have your Access key
and Secret access key
, don’t close the window – open the Listmonk settings in a new window and navigate to the “Media upload” tab. Fill up the information as shown below, make sure to edit your own region, and your own bucket name.
- Send a test email campaign
Make sure everything is working by creating a test campaign with an image and sending it to yourself. If you’ve followed the steps correctly, a new test email from your newsletter should have arrived in your inbox!
- [Optional] Configure bounces and blocklist bad emails
Handling bounces and complaints is key if you don’t want your mail-sending account banned. Services like AWS SES take bounces and complaints very seriously, and require you to stay below a certain threshold of complaints, or they’ll stop you from sending emails.
You get bounced emails when you send emails to addresses that don’t accept any emails (like fake addresses, mistyped addresses, or addresses that have blocked incoming email). You get complaints when users report your email as spam.
If you don’t react to this and keep sending emails to addresses that either bounce or complain about your emails, your percentage of bounced and complained emails over total emails sent will keep increasing, and your account will get banned.
The best way to react to bounces and complaints is to add conflictive email addresses to the blocklist, so you don’t send them any more emails in the future.
This is a feature that comes with Listmonk, but it requires us to set it up correctly in Amazon AWS so that AWS SES knows how to notify our Listmonk instance when there’s a bounce or complaint.
The first thing we want to do is to go to the “Bounces” tab of our Listmonk settings and toggle on “Enable bounce processing”, “Enable bounce webhooks”, and “Enable SES”. Click “Save”.
Then, we need to do a few cumbersome, but easy, steps to link AWS SES to Listmonk. The official Listmonk docs explain in good detail how to do it, please follow their steps now. In a nutshell: you need to create a SNS “Standard” topic, create a HTTPS subscription to that topic with endpoint https://newsletter.mydomain.com/webhooks/service/ses
, and add that subscription to SES under “Feedback notifications” both for “Bounce feedback” and “Complaint feedback”.
If you’ve set it right, bounce and complain addresses will get added to the blocklist and unsubscribed from your mailing lists.
One way to test it is to manually add bounce@simulator.amazonses.com
and complaint@simulator.amazonses.com
to your mailing list and send them a test email campaign (or campaign preview test). If everything is working, you’ll see the bounces in Listmonk under Subscribers > Bounces
, and you’ll see the offending emails being automatically added to the blocklist in the subscribers list under Subscribers > All subscribers
And that’s it!
You are now able to use Listmonk as a Mailchimp replacement to manage your email marketing campaigns and send emails to thousands of addresses for pennies.
The total cost of this setup is around $5/mo for the server and $1 for every 10k emails sent, which means you can run the whole thing for less than a cup of coffee a month if you don’t send many emails. This makes Listmonk on AWS a great Mailchimp alternative for nonprofits, for example – or any other kind of project running on a tight budget. You can send transactional emails, marketing emails, create and grow a newsletter – and even send SMS / texts, Whatsapp messages, and more!
Please let me know in the comments if you got it up and running! It’s nice to hear this tutorial was useful to other people, and your feedback will make this guide even better!
Subscribe to my newsletter
Read articles from Ewan Mak directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Ewan Mak
Ewan Mak
Crafting seamless user experiences with a passion for headless CMS, Vercel deployments, and Cloudflare optimization. I'm a Full Stack Developer with expertise in building modern web applications that are blazing fast, secure, and scalable. Let's connect and discuss how I can help you elevate your next project!