TL;DR
You can replace Google Workspace ($6/user/month) with Mailu — a Docker-based open source mail server — and pay only server costs (~$6-12/month). It's a legitimate path for technical teams prioritizing privacy and cost control. But self-hosting email is genuinely hard: DNS misconfiguration means your emails go to spam, IP reputation takes weeks to build, and a single mistake can get your IP blacklisted. This guide walks through the full setup and helps you decide if it's worth it.
Key Takeaways
- Mailu is a Docker-first mail server — SMTP, IMAP, webmail, spam filtering, and admin UI in one stack
- DNS records are the hardest part — MX, SPF, DKIM, DMARC, and PTR records must all be correct for deliverability
- IP warm-up is mandatory — Gmail and Outlook apply strict filtering to new IPs; ramp up slowly
- Mailu vs Mailcow: Mailu = simpler, better docs; Mailcow = more features, bigger community
- When to self-host email: privacy-critical orgs, developers learning the stack, personal domains
- When NOT to: transactional email (use Resend/Postmark instead), teams without a sysadmin
Should You Self-Host Email?
Be honest about the trade-offs before starting.
Self-hosting email is right for:
- Personal or organizational domains where privacy matters (no Google scanning your emails)
- Technical teams with a dedicated sysadmin
- Learning how email infrastructure works
- Cost reduction at scale (10+ mailboxes)
Don't self-host email if:
- You need transactional email (welcome emails, password resets) — use Resend or Postmark instead
- You don't have time to maintain it (spam filters update constantly)
- Your IP address changes or you're on a residential connection
- You need Google Workspace's collaborative features (Docs, Calendar, Meet)
Rule of thumb: Self-host email only if you're willing to own the deliverability problem. It works, but it requires ongoing attention.
Mailu vs Mailcow: Which Self-Hosted Email Server?
The two dominant Docker-based mail servers:
| Feature | Mailu | Mailcow |
|---|---|---|
| Setup complexity | ⭐ Simpler | More complex |
| GitHub Stars | ~6,500 | ~9,000 |
| Webmail | Roundcube included | SOGo + Roundcube |
| Admin UI | ✅ Clean | ✅ Feature-rich |
| Spam filtering | Rspamd | Rspamd |
| 2FA | ✅ | ✅ |
| ARM support | ✅ | Limited |
| Kubernetes support | ✅ | ❌ |
| Documentation | Good | Excellent |
| Community | Medium | Large |
| Best for | Simplicity | Full-featured deployments |
Recommendation: Start with Mailu if you want a simpler setup. Switch to Mailcow if you need more features or find Mailu limiting.
Part 1: Server Prerequisites
VPS Requirements
Email requires a dedicated static IP — not a shared host:
- Minimum: 2 vCPU, 2 GB RAM, 20 GB storage
- Recommended: Hetzner CX22 (€4.35/month) — dedicated IP included
- Critical: Your provider must allow port 25 (SMTP). Some cloud providers block it by default. Hetzner, OVH, and most VPS providers allow it; AWS, GCP, and Azure block port 25 by default.
Check Port 25
Before installing anything, verify your VPS can send on port 25:
# Check if port 25 is open (from your VPS):
telnet smtp.gmail.com 25
# If it times out, your provider is blocking it
Reverse DNS (PTR Record)
This is non-negotiable. Your IP address must resolve back to your mail server hostname. Set this in your VPS provider's control panel:
YOUR_SERVER_IP → mail.yourdomain.com
Hetzner: Server → Networking → Edit PTR record
DigitalOcean: Networking → Domains → Add reverse record
Part 2: DNS Configuration
Before installing Mailu, configure all DNS records (these take up to 48 hours to propagate):
Required Records
# MX record — tells other servers where to deliver email
yourdomain.com. IN MX 10 mail.yourdomain.com.
# A record — IP of your mail server
mail.yourdomain.com. IN A YOUR_SERVER_IP
# SPF — which servers can send mail for your domain
yourdomain.com. IN TXT "v=spf1 ip4:YOUR_SERVER_IP ~all"
# DMARC — policy for failed authentication (start permissive)
_dmarc.yourdomain.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com"
DKIM: Generated by Mailu after installation — add after setup.
Autoconfig Records (optional but recommended)
These allow email clients (Thunderbird, Outlook) to auto-configure:
autoconfig.yourdomain.com. IN CNAME mail.yourdomain.com.
autodiscover.yourdomain.com. IN CNAME mail.yourdomain.com.
Part 3: Install Mailu
Generate Configuration
Use Mailu's official setup wizard at setup.mailu.io to generate your docker-compose.yml and mailu.env.
Key settings to configure:
-
Domain:
yourdomain.com -
Hostname:
mail.yourdomain.com -
TLS flavor:
letsencrypt(automatic SSL) -
Webmail:
roundcube(recommended)
Download both generated files to your server:
mkdir /mailu && cd /mailu
# Download the generated files from setup.mailu.io
# Or use the config generator CLI
Deploy
cd /mailu
docker compose up -d
Mailu starts the following services:
- front — Nginx reverse proxy + SSL termination
- admin — Web admin interface
- imap — Dovecot IMAP server
- smtp — Postfix SMTP server
- antispam — Rspamd
- webmail — Roundcube
Create Your First Admin Account
docker compose exec admin flask mailu admin admin yourdomain.com 'SecurePassword123'
# Creates admin@yourdomain.com with admin privileges
Access the admin UI at https://mail.yourdomain.com/admin.
Part 4: Configure DKIM
DKIM keys are generated by Mailu on startup. Retrieve your public key:
docker compose exec admin flask mailu dkim yourdomain.com
This outputs a DNS TXT record like:
dkim._domainkey.yourdomain.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0..."
Add this to your DNS. After propagation (up to 48 hours), verify:
# Verify DKIM is publishing correctly:
dig TXT dkim._domainkey.yourdomain.com
Tighten DMARC After Verification
Once SPF and DKIM are working (check via mail-tester.com):
# Phase 1 — monitor only:
_dmarc.yourdomain.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com"
# Phase 2 — quarantine (after 2 weeks of clean reports):
_dmarc.yourdomain.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com"
# Phase 3 — reject (full enforcement):
_dmarc.yourdomain.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com"
Part 5: Test Deliverability
Before sending any real email, verify your setup:
# 1. Test DNS records:
dig MX yourdomain.com
dig TXT yourdomain.com # Should show SPF
dig TXT dkim._domainkey.yourdomain.com # Should show DKIM
dig TXT _dmarc.yourdomain.com # Should show DMARC
# 2. Check blacklists (run from your server):
curl -s "https://api.hetrixtools.com/v2/blacklist-check/YOUR_SERVER_IP/"
# 3. Send a test email to mail-tester.com:
# Visit mail-tester.com, get a unique address, send to it, check your score
# Aim for 9/10 or higher before sending real email
IP Warm-Up Schedule
Gmail and Outlook treat new IPs with heavy suspicion. Follow this ramp-up:
Week 1: 10-50 emails/day (to engaged recipients only)
Week 2: 50-200 emails/day
Week 3: 200-500 emails/day
Week 4+: Scale gradually based on bounce/spam rates
Never blast a large list from a new IP. The first emails should go to people who know you and will mark them as "not spam" if needed.
Part 6: Adding Mailboxes
Via the admin UI at https://mail.yourdomain.com/admin:
- Users → Add User → Set email, password, quota
-
Aliases → Add alias (e.g.,
hello@→admin@) - Domains → Add additional domains (multi-domain setup)
Or via CLI:
# Add a user:
docker compose exec admin flask mailu user jane yourdomain.com 'Password123'
# Add an alias:
docker compose exec admin flask mailu alias info yourdomain.com jane
Connecting Email Clients
Mailu auto-generates client configuration for:
-
IMAP:
mail.yourdomain.com:993(SSL/TLS) -
SMTP:
mail.yourdomain.com:587(STARTTLS) -
Webmail:
https://mail.yourdomain.com
For Thunderbird, the autoconfig endpoint auto-detects settings when you enter your email address.
Ongoing Maintenance
Self-hosting email requires ongoing attention:
Monthly tasks:
- Check spam score at mail-tester.com
- Review DMARC reports (if using a reporting service like DMARC Analyzer)
- Check your IP against blacklists
When updates release:
cd /mailu
docker compose pull && docker compose up -d
Backup email data:
# Backup mailboxes (Dovecot IMAP storage):
tar -czf mail-backup-$(date +%Y%m%d).tar.gz /mailu/mail/
Cost Comparison
| Option | Monthly Cost (5 users) | Notes |
|---|---|---|
| Google Workspace Starter | $30/mo | $6/user |
| Microsoft 365 Business Basic | $30/mo | $6/user |
| Fastmail | $25/mo | $5/user |
| Mailu (self-hosted) | ~$6-12/mo | Server cost only |
| Proton Mail Plus | $50/mo | Privacy-focused managed |
Self-hosting saves ~$25-50/month for a 5-person team — meaningful for bootstrapped startups, but less meaningful once you factor in maintenance time.
Methodology
- Mailu documentation: mailu.io/docs
- Mailu GitHub: github.com/Mailu/Mailu
- Email authentication specs: Google, DMARCLY, RFC standards
- Comparison sources: RunCloud, GeekFlare, It's FOSS (2025-2026)
Compare all open source Google Workspace alternatives at OSSAlt.com.
Top comments (1)
We run Postfix and Dovecot with Roundcube in our panel, and the part that still trips people up is PTR. I have seen people fix SPF and DKIM for hours while the real problem was that the PTR was still set to the default VPS hostname at the provider, not at the registrar. I now check dig -x first, before I touch any other record.