Self-Hosting Email with Mailcow: A 6-Month Production Reality Check

HomeLab tutorial - IT technology blog
HomeLab tutorial - IT technology blog

Why I Ditched Managed Email Hosting

After shelling out $6 per user every month for Google Workspace, I finally decided to reclaim my data. Self-hosting email has a reputation for being a sysadmin’s nightmare. However, after running Mailcow in production for over 180 days, I’ve found that the “nightmare” is mostly a series of DNS hurdles that anyone can clear. My server currently handles three domains and about 50 emails daily with zero downtime and perfect deliverability.

Mailcow is more than just a mail server; it’s a dockerized ecosystem. It bundles Postfix for sending, Dovecot for storage, Rspamd for filtering, and the SOGo webmail interface. It handles the heavy lifting of container orchestration so you don’t have to manually edit cryptic config files for hours.

The Prerequisites: Don’t Skimp on Hardware

Before you run a single command, you need the right foundation. I initially tried a 2GB RAM VPS, and it was a disaster. ClamAV (antivirus) and Solr (search indexing) are memory hogs. For a smooth experience, you need a Linux VPS with at least 4GB of RAM—though 8GB is the sweet spot if you want the web interface to feel snappy.

Crucially, verify that your provider allows traffic on Port 25. Providers like DigitalOcean, Vultr, and AWS block this by default for new accounts. You often have to open a support ticket and explain your use case to get it unblocked. If they refuse, your server will never be able to send mail.

1. Prepare the Environment

Start with a clean Ubuntu 22.04 or 24.04 LTS installation. Update your packages and install the Docker engine.

sudo apt update && sudo apt upgrade -y
sudo apt install curl git -y
curl -sSL https://get.docker.com/ | CHANNEL=stable sh
sudo systemctl enable --now docker

2. Clone and Configure

I recommend keeping all Docker services in /opt for better organization. This makes backups much easier to manage later.

cd /opt
git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized
./generate_config.sh

The script will prompt you for your Fully Qualified Domain Name (FQDN), such as mail.yourdomain.com. Make sure this subdomain points to your server’s IP address before running the script.

3. Launching the Stack

docker compose pull
docker compose up -d

Give it about two minutes to initialize all 17+ containers. You can then access the dashboard at your FQDN. Log in with the default credentials admin / moohoo and change them immediately. Seriously—do it now.

The Three Pillars of Deliverability

Setting up the server takes ten minutes. Getting Big Tech (Gmail/Outlook) to trust you takes a bit more effort. If your DNS isn’t perfect, your mail will vanish into spam folders. I used these exact settings to maintain a 10/10 score on Mail-Tester.

SPF (Sender Policy Framework)

This record authorizes your server’s IP to send mail on your behalf. It’s a simple TXT record in your DNS settings.

v=spf1 ip4:1.2.3.4 -all

Use -all (Hard Fail) instead of ~all (Soft Fail). It tells receiving servers to reject anything that doesn’t come from your IP, which significantly boosts your reputation.

DKIM (DomainKeys Identified Mail)

Mailcow signs every outgoing email with a digital signature. In the Mailcow UI, head to Configuration > DNS Records to generate your key. Copy that public key into a TXT record for the dkim._domainkey selector in your DNS provider (like Cloudflare or Namecheap).

DMARC (Reporting and Conformance)

DMARC tells other servers what to do if SPF or DKIM fails. I suggest starting with a ‘quarantine’ policy.

v=DMARC1; p=quarantine; rua=mailto:[email protected]

The Non-Negotiable PTR Record

Your IP address must resolve back to your mail domain. This is called a Reverse DNS (rDNS) or PTR record. You cannot set this in your domain’s DNS panel; you must set it in your VPS provider’s dashboard. Without this, Gmail will bounce your emails instantly with a 550 error.

The “Dirty IP” Problem: Using an SMTP Relay

Sometimes, you do everything right, but your VPS provider’s IP range is already blacklisted because of a previous tenant’s spam. If you find yourself on the Spamhaus blocklist, don’t give up. I solved this by routing outgoing mail through an SMTP relay.

Mailcow handles this natively. You can use a service like Amazon SES, which is incredibly cheap—roughly $0.10 for every 1,000 emails. In the Mailcow UI, go to Configuration > Setup > Routing and add your SES credentials. Your server still handles all incoming mail and storage, but Amazon handles the “handshake” with the outside world.

Maintenance Habits for a Healthy Server

You can’t just set this up and forget it. Here is how I’ve kept my instance running smoothly for six months:

  • Nightly Backups: Use the built-in script in ./helper-scripts/backup_and_restore.sh. I have a cron job that runs this at 3:00 AM and rsyncs the 4GB backup folder to an off-site storage box.
  • Rspamd Tuning: Check the Rspamd stats once a week. If you notice specific spam patterns, you can easily adjust the weight of certain symbols to block them before they hit your inbox.
  • Stay Updated: Mailcow moves fast. Run ./update.sh once a month to pull security patches and new features. Always take a snapshot of your VPS before updating.
  • Watch the RAM: If your 4GB server starts swapping, disable ClamAV in mailcow.conf (SKIP_CLAMD=y). You’ll lose built-in virus scanning, but you’ll save nearly 1GB of RAM.

Self-hosting email is a commitment, but the payoff is total privacy and a much deeper understanding of how the internet actually works. If you follow the DNS rules and keep your software updated, Mailcow is a rock-solid alternative to the big providers.

Share: