Skip to main content

Self-Hosting Listmonk Email Newsletters 2026

·OSSAlt Team
listmonkemailself-hostingdockerguide
Share:

Listmonk is the fastest open source newsletter tool — a single Go binary that can send 100,000+ emails per hour. Self-hosting replaces Mailchimp, ConvertKit, and Buttondown at a fraction of the cost. No per-subscriber pricing.

Requirements

  • VPS with 512 MB RAM minimum
  • Docker and Docker Compose
  • Domain name (e.g., mail.yourdomain.com)
  • SMTP service (Amazon SES, Resend, SendGrid)
  • DNS access for SPF/DKIM/DMARC records
  • 5+ GB disk

Step 1: Create Docker Compose

# docker-compose.yml
services:
  listmonk:
    image: listmonk/listmonk:latest
    container_name: listmonk
    restart: unless-stopped
    ports:
      - "9000:9000"
    volumes:
      - ./config.toml:/listmonk/config.toml
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    container_name: listmonk-db
    restart: unless-stopped
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=listmonk
      - POSTGRES_USER=listmonk
      - POSTGRES_PASSWORD=your-strong-password

volumes:
  postgres_data:

Step 2: Create Configuration

Create config.toml:

[app]
address = "0.0.0.0:9000"
admin_username = "admin"
admin_password = "your-admin-password"

[db]
host = "db"
port = 5432
user = "listmonk"
password = "your-strong-password"
database = "listmonk"
ssl_mode = "disable"
max_open = 25
max_idle = 25
max_lifetime = "300s"

Step 3: Initialize Database

# Start database first
docker compose up -d db

# Run database setup
docker compose run --rm listmonk ./listmonk --install

# Start Listmonk
docker compose up -d

Step 4: Reverse Proxy (Caddy)

# /etc/caddy/Caddyfile
mail.yourdomain.com {
    reverse_proxy localhost:9000
}
sudo systemctl restart caddy

Step 5: Configure SMTP

In SettingsSMTP:

ProviderHostPortAuth
Amazon SESemail-smtp.us-east-1.amazonaws.com587SMTP credentials
Resendsmtp.resend.com587API key
SendGridsmtp.sendgrid.net587API key
Mailgunsmtp.mailgun.org587API key
Brevosmtp-relay.brevo.com587API key

SMTP configuration in Listmonk:

  1. SettingsSMTPAdd new
  2. Enter host, port, auth type, credentials
  3. Set max connections (5-10 for most providers)
  4. Set retries and wait time
  5. Test the connection

Cost comparison for 50K emails/month:

ProviderPrice
Amazon SES$5
Resend$20
SendGrid$15
BrevoFree (300/day)
Mailgun$35

Step 6: Set Up DNS Records

Required for deliverability:

# SPF — authorize your SMTP provider
yourdomain.com  TXT  "v=spf1 include:amazonses.com ~all"

# DKIM — sign your emails (get from SMTP provider)
selector._domainkey.yourdomain.com  TXT  "v=DKIM1; k=rsa; p=..."

# DMARC — tell receivers what to do with failed auth
_dmarc.yourdomain.com  TXT  "v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com"

# Return-Path (optional but recommended)
bounce.yourdomain.com  CNAME  feedback-smtp.us-east-1.amazonses.com

Step 7: Create Subscriber Lists

  1. ListsCreate new
  2. Create lists like:
    • Newsletter (public, double opt-in)
    • Product Updates (public, double opt-in)
    • Internal (private, single opt-in)

Import subscribers:

  1. SubscribersImport
  2. Upload CSV with columns: email, name, list
  3. Map fields and import

Step 8: Create Email Templates

Listmonk uses Go templates:

{{ template "header" . }}

<h1>{{ .Campaign.Subject }}</h1>

<p>Hey {{ .Subscriber.FirstName }},</p>

{{ .Campaign.Body }}

<p>
  <a href="{{ .Campaign.URL }}">Read more →</a>
</p>

{{ template "footer" . }}

Template variables:

VariableValue
{{ .Subscriber.Email }}Subscriber email
{{ .Subscriber.FirstName }}First name
{{ .Subscriber.LastName }}Last name
{{ .Campaign.Subject }}Campaign subject
{{ .Campaign.Body }}Campaign content
{{ .UnsubscribeURL }}Unsubscribe link

Step 9: Create and Send Campaigns

  1. CampaignsCreate new
  2. Write content using the rich text editor or HTML
  3. Select target lists
  4. Preview and test (send test email to yourself)
  5. Schedule or send immediately

Campaign types:

  • Regular — one-time send
  • Optin — double opt-in confirmation

Step 10: Add Subscription Forms

Embed form on your website:

<form method="post" action="https://mail.yourdomain.com/subscription/form">
  <input type="hidden" name="nonce" />
  <input type="email" name="email" required placeholder="your@email.com" />
  <input type="text" name="name" placeholder="Your name" />
  <input type="hidden" name="l" value="YOUR_LIST_UUID" />
  <button type="submit">Subscribe</button>
</form>

API subscription:

curl -X POST 'https://mail.yourdomain.com/api/subscribers' \
  -u 'admin:your-admin-password' \
  -H 'Content-Type: application/json' \
  --data '{
    "email": "user@example.com",
    "name": "User Name",
    "lists": [1],
    "status": "enabled"
  }'

Production Hardening

Performance tuning:

[app]
concurrency = 10           # Concurrent campaign workers
message_rate = 100         # Emails per second
batch_size = 1000          # Batch size per worker

Backups:

# Database backup (daily cron)
docker exec listmonk-db pg_dump -U listmonk listmonk > /backups/listmonk-$(date +%Y%m%d).sql

Updates:

docker compose pull
docker compose up -d

Monitoring:

  • Monitor port 9000 with Uptime Kuma
  • Track bounce rates (keep under 2%)
  • Monitor SMTP queue depth
  • Check DMARC reports for delivery issues

Resource Usage

SubscribersRAMCPUDisk
1-10K256 MB1 core2 GB
10K-100K512 MB2 cores5 GB
100K-1M1 GB4 cores20 GB

Listmonk is extraordinarily lightweight — the Go binary uses minimal resources.

VPS Recommendations

ProviderSpecPrice
Hetzner2 vCPU, 2 GB RAM€4.50/month
DigitalOcean1 vCPU, 1 GB RAM$6/month
Linode1 vCPU, 1 GB RAM$5/month

Total cost: VPS ($5) + SMTP ($5 SES) = $10/month for 50K+ emails. Mailchimp would charge $299/month for 50K subscribers.

Why Self-Host Listmonk

The email marketing SaaS pricing model is built on subscriber counts, and costs escalate rapidly as lists grow. Mailchimp's Essentials plan starts at $13/month for 500 subscribers and reaches $299/month at 50,000 subscribers. ConvertKit charges $166/month for 25,000 subscribers on their Creator Pro plan. Buttondown is more reasonable at $100/month for 50,000 subscribers — but it's still $1,200/year for a service that's fundamentally "send emails from a database."

Self-hosted Listmonk changes this economics entirely. Listmonk itself is free and open source. Your costs become the VPS (as low as €3.79/month on Hetzner) plus your SMTP provider. Amazon SES charges $0.10 per 1,000 emails — 50,000 emails costs $5. That's $10/month total for a list that would cost $299/month on Mailchimp, or $3,468/year in savings. For newsletters with 200,000+ subscribers, the savings exceed $10,000/year.

No subscriber limits, no sending limits: Listmonk imposes no caps at the software level. Your only constraints are your VPS capacity (easily scaled) and your SMTP provider's limits (which are far higher than newsletter SaaS caps at equivalent prices). A single Hetzner server can run campaigns for lists of millions.

Data ownership: Your subscriber list is among your most valuable business assets. With SaaS newsletter platforms, your list lives in a third party's database, subject to their terms of service, their data breach risk, and their business continuity. Self-hosting means your subscriber data is under your direct control and stays within your infrastructure.

When NOT to self-host Listmonk: If you're just starting a newsletter with fewer than 1,000 subscribers, the free tiers on Mailchimp or Buttondown are genuinely simpler. Listmonk requires managing DNS records (SPF/DKIM/DMARC), monitoring bounce rates, and handling deliverability issues — tasks that managed platforms abstract away. If email marketing is a side project rather than a core business function, the operational overhead may not be worth the cost savings at small scale.

Prerequisites (Expanded)

512 MB RAM minimum: Listmonk is a Go binary and has a genuinely tiny memory footprint — it runs comfortably in 128 MB. The 512 MB minimum accounts for PostgreSQL running on the same host. If you're co-hosting Listmonk with other services on a shared VPS (which is practical given its low resource usage), factor their requirements into your total RAM budget.

SMTP service: Listmonk sends email but does not include an SMTP server. You need an external SMTP provider for delivery. The most cost-effective option for high-volume sending is Amazon SES ($0.10/1,000 emails), but it requires requesting production access from AWS. Resend and Brevo are simpler to set up and suitable for most use cases. Never attempt to send newsletter email directly from your VPS IP — it will land in spam immediately.

DNS access for SPF/DKIM/DMARC: Email deliverability requires DNS configuration. Without proper SPF, DKIM, and DMARC records, your emails will be filtered as spam by Gmail, Yahoo, and Microsoft. This is not optional for production newsletters — budget 30 minutes for initial DNS configuration and 24–48 hours for propagation before testing deliverability.

5+ GB disk: Listmonk stores subscriber data, campaign history, and analytics in PostgreSQL. At 100,000 subscribers, the database is a few hundred MB. The bigger disk consumer is campaign archives and attachment storage if you use those features.

For VPS selection, Listmonk is one of the few applications that runs comfortably on the cheapest tier of any major provider. See the VPS comparison for self-hosters for current pricing across providers. Hetzner's CX11 (€3.79/month) or DigitalOcean's $6/month Droplet are sufficient for lists up to 100,000 subscribers.

Production Security Hardening

Listmonk holds your entire subscriber list — names, email addresses, and custom attributes. It's a high-value target. Treat its security accordingly.

Firewall with UFW: Expose only ports 80, 443, and 22. Listmonk runs on port 9000 internally, which should never be directly accessible from the internet — only via your reverse proxy.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Fail2ban: Protect the admin panel from brute-force login attempts.

sudo apt install fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Keep secrets out of config.toml: The admin_password and database password in config.toml are plaintext. Restrict file permissions so only the running user can read it:

chmod 600 config.toml

In production, consider using environment variable overrides instead of embedding credentials in the config file.

Disable SSH password authentication:

sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd

Enable automatic security updates:

sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

Set up automated database backups: Your subscriber list and campaign history live entirely in PostgreSQL. An accidental docker compose down -v or disk failure without backups means losing your entire list. Set up daily automated backups with off-site copies. See automated server backups with restic for a step-by-step backup strategy that handles PostgreSQL dumps with off-site replication to S3 or Backblaze B2.

For a complete hardening checklist, see the self-hosting security checklist.

Troubleshooting Common Issues

Campaigns stuck in "Running" state

If a campaign starts but never finishes sending, the most common cause is SMTP configuration. Check the campaign's send status in the Listmonk admin, then verify your SMTP settings:

  1. Go to Settings → SMTP and click Test
  2. If the test fails, check the error message — authentication failures, TLS negotiation errors, and port blocking are the most frequent issues
  3. Check the Listmonk container logs: docker compose logs listmonk

Amazon SES sandbox mode is a common gotcha: in sandbox, you can only send to verified email addresses. Request production access from AWS before launching a real campaign.

Emails going to spam

Open DMARC reports by setting rua=mailto:dmarc@yourdomain.com in your DMARC record and monitoring reports using a free tool like MXToolbox. Common deliverability issues:

  • SPF record not covering your SMTP provider's sending IPs
  • DKIM not set up with your SMTP provider
  • Sending from an IP shared with other senders who have bad reputation (less common with major providers)
  • No DMARC record at all (some providers now require it)

Check your domain's health at mail-tester.com before sending your first real campaign.

Database connection error on startup

If Listmonk exits with dial tcp: connection refused pointing to the DB host, the PostgreSQL container hasn't finished initializing. Add a healthcheck to the db service in your Compose file, or simply wait 10 seconds and restart: docker compose restart listmonk.

Import fails for large CSV files

Listmonk's default upload limit may be too small for very large subscriber CSV files. The import progress is visible in Subscribers → Import, and failed imports show an error message. For imports over 50,000 rows, use the API endpoint with chunked uploads rather than the web interface.

Subscription form returns 403

Listmonk's CSRF protection requires the hidden nonce field in subscription forms. Ensure the form includes <input type="hidden" name="nonce" /> — even though it's empty, its presence is required. Also check that your Caddy/Nginx proxy is forwarding the correct headers including X-Forwarded-For and X-Real-IP.

Listmonk vs Mailchimp vs Other Self-Hosted Options

Listmonk sits in the self-hosted newsletter space alongside tools like Mautic and Sendy. Understanding when Listmonk is the right choice helps clarify its role.

Listmonk is purpose-built for the newsletter and transactional email use case. Its campaign management, subscriber list handling, and templating system are polished and production-ready. The Go binary is lightweight and fast. For developers and technical teams running newsletters at any scale (from a few hundred to millions of subscribers), Listmonk is the cleanest self-hosted option because it does one thing well without unnecessary complexity.

Mautic is a broader marketing automation platform — it handles email campaigns but also lead scoring, CRM features, and multi-channel marketing workflows. If your use case extends beyond newsletters into marketing automation, Mautic's additional features may justify its higher resource requirements and configuration overhead. For pure newsletter use cases, Mautic is overkill.

Sendy is a PHP application that front-ends Amazon SES for bulk email. It's self-hosted but requires SES for sending — you're still dependent on a cloud email infrastructure. Listmonk is fully self-contained with your SMTP provider, giving you more flexibility to switch providers or run your own mail server.

Mailchimp charges $13/month at entry level and scales steeply with subscriber count — $299/month for 50,000 subscribers. Listmonk on a $10/month VPS handles that same subscriber count with no per-subscriber fee. For growing email lists, self-hosting Listmonk becomes increasingly compelling as Mailchimp's pricing tiers escalate.

See the best open source email marketing tools for a full comparison of newsletter and email automation platforms.

Compare email newsletter tools on OSSAlt — features, deliverability, and pricing side by side.

See open source alternatives to Listmonk on OSSAlt.

The SaaS-to-Self-Hosted Migration Guide (Free PDF)

Step-by-step: infrastructure setup, data migration, backups, and security for 15+ common SaaS replacements. Used by 300+ developers.

Join 300+ self-hosters. Unsubscribe in one click.