by Volodymyr Lukianenko
email-marketing listmonk migration self-hosting

Why we left Mailchimp

Mailchimp is great if you have 500 subscribers and send one newsletter a month. At 10K subscribers, the Standard plan costs €110/month. At 15K, it jumps again. The pricing scales with your audience, not with the value you get.

We run TheStackTax — a catalog of self-hosted alternatives. We practice what we preach. Our newsletter runs on listmonk, deployed on the same VPS that powers this site.

Here’s how we did it.

Step 1: Export your Mailchimp data

Before touching anything, export your audience:

  1. Go to Audience → Manage Audience → Export Audience
  2. Export as CSV
  3. Download all files (they’ll email you a link)

Important: Mailchimp unsubscribes are legally protected. Don’t re-import them. Clean your CSV first — remove rows with unsubscribed status.

Step 2: Deploy listmonk

We deployed listmonk on the same Hostinger VPS that runs our other services. Here’s our docker-compose.yml:

services:
  listmonk:
    image: listmonk/listmonk:latest
    container_name: listmonk
    restart: unless-stopped
    volumes:
      - ./config.toml:/listmonk/config.toml:ro
    networks:
      - proxy
      - internal
    command: >
      sh -c "./listmonk --install --idempotent --yes &&
             ./listmonk --upgrade --yes &&
             ./listmonk"

  listmonk_db:
    image: postgres:17
    container_name: listmonk_db
    restart: unless-stopped
    environment:
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_USER=listmonk
      - POSTGRES_DB=listmonk
    volumes:
      - listmonk_db:/var/lib/postgresql/data
    networks:
      - internal

Key decisions:

  • PostgreSQL 17, not 13 (the default in listmonk’s compose)
  • No host port — accessible only through Caddy reverse proxy
  • --idempotent --yes — safe to restart, won’t break on existing DB

Step 3: Configure SMTP

listmonk needs an SMTP provider to send emails. We use Amazon SES:

  1. Verify your domain in SES
  2. Create SMTP credentials
  3. Add them to listmonk’s Settings → SMTP tab

Without SMTP, subscribers can sign up but won’t receive confirmation emails. Make this your first priority after deployment.

Step 4: Import your subscribers

listmonk’s CSV import is straightforward:

  1. Go to Subscribers → Import
  2. Upload your cleaned CSV
  3. Map columns (email → Email, name → Name)
  4. Choose “Skip duplicates”
  5. Import

We imported 200+ subscribers. Zero bounces on the first campaign — listmonk’s email validation is solid.

Step 5: Create your first campaign

listmonk’s campaign editor is minimal but powerful:

  • WYSIWYG editor with raw HTML mode
  • Template variables for personalization ({{ .Subscriber.Name }})
  • Scheduling with timezone awareness
  • Analytics — opens, clicks, views (privacy-respecting, no pixel tracking)

The numbers

Mailchimplistmonk
Monthly cost€110€5 (VPS share + SES)
Subscriber limit10KUnlimited
AutomationIncludedManual (via n8n)
Pixel trackingYesOptional, off by default
Data ownershipCloudYour server

Annual saving: €1,260. The migration took 3 hours total.

What we miss

listmonk is not a 1:1 replacement. Here’s what you’ll need to work around:

  • No drag-and-drop builder — you edit HTML directly
  • No marketing automation — combine with n8n for sequences
  • No A/B testing — send variants manually and compare

For us, these are acceptable trade-offs. We value data ownership and cost control over visual builders.

Should you do it?

If you have:

  • 5K+ subscribers (the cost difference matters)
  • Comfortable editing HTML
  • Someone who can handle Docker

Then yes. The savings are real, and the control is liberating.

If you don’t want to do it yourself — we can deploy listmonk for you. We’ve done it. We run it. We’ll set it up on your VPS in an afternoon.