The Dream vs. The Reality
Someone in every self-hosting forum, at least once a week, says it: “Just host your own email server.” And they’re not wrong in spirit. But they are deeply, tragically wrong about how much pain that involves.
Running a full mail server — Postfix, Dovecot, SpamAssassin, OpenDKIM, the works — means spending your weekend configuring PTR records, begging your VPS provider to unblock port 25, convincing Gmail that you’re not a bot farm, and watching your carefully crafted newsletters land directly in spam because your IP used to belong to someone who sold Viagra in 2009.
Here’s the thing: you probably don’t actually need to run your own mail server. What you actually want is to give a unique email address to every website you sign up for, on your own domain, so when DataBreach #4,729 happens you can trace exactly who sold your email and nuke that alias without touching your real inbox.
That’s email aliasing. And it’s a completely different — and significantly saner — problem.
Why Aliasing Beats the Full Server
Full self-hosted email is a two-part problem: receiving mail and sending mail. Receiving is honestly fine. Your server gets an MX record, accepts connections on port 25, done. Not trivial, but doable.
Sending is where everything catches fire.
Deliverability to Gmail, Outlook, and Yahoo is gated behind a wall of reputation signals: IP warmup history, DMARC/DKIM/SPF alignment, reverse PTR records that match your hostname, and the general goodwill of major providers who can reject your mail for vibes alone. Commercial email services like Postmark and AWS SES exist specifically because building and maintaining sender reputation is a full-time job.
Aliasing sidesteps all of this. The aliasing server receives mail on your domain and forwards it to your real account (Gmail, Proton, Fastmail — whatever you already trust). You never need to send cold mail from your own IP. When you reply through an alias, the aliasing layer rewrites headers so your real address stays hidden, then routes the outbound message through a configured SMTP relay with proper reputation.
Your job: set up MX records, configure SPF/DKIM/DMARC, and point a working SMTP relay at your aliasing server. That’s it.
The Two Contenders
Two projects dominate the self-hostable aliasing space.
SimpleLogin — Proton acquired this in 2022, which either reassures you or makes you suspicious depending on your threat model. The good news: it’s still open source and fully self-hostable. It has polished mobile apps, browser extensions for every major browser, and a web UI that doesn’t look like it was designed by a sysadmin on their lunch break. SimpleLogin supports sending through aliases (reply and compose), custom domains, PGP encryption between server and registered users, and multiple inboxes per account. The self-hosted path uses Docker and is reasonably well-documented.
addy.io (formerly AnonAddy) — Pure open source, community-driven, no acquisition story to worry about. The self-hosted setup is similarly Docker-based. The web UI is solid; mobile apps exist but are less polished than SimpleLogin’s. addy.io supports multiple aliases per recipient, custom domains, bandwidth-based limits (configurable when self-hosting), and similar reply-through-alias behavior. If you’re already paying for Proton services and want SimpleLogin’s hosted tier “for free,” you get it. If you want no corporate parent anywhere near your privacy stack, addy.io is your call.
Honestly? Both are good. The architectural difference is mostly vibes and ecosystem preferences.
Architecture in 30 Seconds
Spammy Website → sends to [email protected] ↓MX record → your server running SimpleLogin or addy.io ↓Aliasing layer looks up alias → routes to [email protected] ↓Gmail receives forwarded mail (sender: [email protected]) ↓You reply → aliasing layer rewrites From → Spammy Website sees alias, not GmailYour real address never leaves the aliasing server. When a site gets breached, you disable that one alias. The rest of your mail is unaffected.
Self-Hosting SimpleLogin
DNS First
Before you touch Docker, get DNS right. You need:
MX record — points your domain’s mail to your server:
yourdomain.com. MX 10 mail.yourdomain.com.mail.yourdomain.com. A YOUR_SERVER_IPSPF — tells receivers who’s allowed to send mail from your domain:
yourdomain.com. TXT "v=spf1 ip4:YOUR_SERVER_IP -all"If you’re routing outbound through Postmark, add their include:
yourdomain.com. TXT "v=spf1 ip4:YOUR_SERVER_IP include:spf.mtasv.net -all"DKIM — cryptographic signature proving the mail came from your server. SimpleLogin generates a keypair on first run. You’ll grab the public key from the container and create a TXT record:
dkim._domainkey.yourdomain.com. TXT "v=DKIM1; k=rsa; p=MIGfMA0GCS..."DMARC — tells receivers what to do with mail that fails SPF/DKIM checks:
_dmarc.yourdomain.com. TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]"Start with p=quarantine instead of p=reject until you’re confident everything is aligned.
PTR record — the reverse DNS entry mapping your server IP back to your hostname. This one’s on your VPS provider’s control panel, not your DNS host. Set YOUR_SERVER_IP → mail.yourdomain.com. Most providers let you do this from the dashboard. Some budget providers don’t. If your provider won’t give you PTR control, your deliverability will be limited — use a proper SMTP relay for outbound.
DKIM Key Generation
Before writing your compose file, generate the keypair SimpleLogin expects:
mkdir -p /opt/simplelogin/dkimopenssl genrsa -out /opt/simplelogin/dkim/dkim.key 2048openssl rsa -in /opt/simplelogin/dkim/dkim.key -pubout -out /opt/simplelogin/dkim/dkim.pub.keyGrab the public key content (strip the header/footer lines, join into one line) — that’s what goes in your DKIM TXT record.
Docker Compose
services: postgres: image: postgres:15-alpine restart: unless-stopped environment: POSTGRES_USER: simplelogin POSTGRES_PASSWORD: changeme_strong_password POSTGRES_DB: simplelogin volumes: - ./postgres-data:/var/lib/postgresql/data
redis: image: redis:7-alpine restart: unless-stopped volumes: - ./redis-data:/data
app: image: simplelogin/app:latest restart: unless-stopped depends_on: - postgres - redis env_file: - .env ports: - "7777:7777" volumes: - ./dkim:/dkim - ./upload:/code/static/upload
email-handler: image: simplelogin/app:latest restart: unless-stopped command: ["python", "email_handler.py"] depends_on: - postgres - redis env_file: - .env ports: - "20381:20381" volumes: - ./dkim:/dkimEnvironment Config
# Domain configURL=https://app.yourdomain.comEMAIL_DOMAIN=yourdomain.comALIAS_DOMAINS=yourdomain.comSUPPORT_EMAIL=[email protected]
# DatabaseDB_URI=postgresql://simplelogin:changeme_strong_password@postgres/simplelogin
# RedisREDIS_URL=redis://redis:6379/0
# Secret key — generate with: python3 -c "import secrets; print(secrets.token_hex(32))"SECRET_KEY=your_generated_secret_key_here
# DKIMDKIM_PRIVATE_KEY_PATH=/dkim/dkim.keyDKIM_DNS_VALUE=dkim._domainkey.yourdomain.com
# Email handlerEMAIL_HANDLER_HOST=email-handlerEMAIL_HANDLER_PORT=20381
# Outbound SMTP — use Postmark, Mailgun, or similarPOSTFIX_SERVER=smtp.postmarkapp.comPOSTFIX_PORT=587POSTFIX_USERNAME=your-postmark-api-tokenPOSTFIX_PASSWORD=your-postmark-api-token
# App settingsDISABLE_REGISTRATION=falseDISABLE_ONBOARDING=falseOne reality check: POSTFIX_SERVER here isn’t actually Postfix. SimpleLogin’s naming is a bit loose — it’s just an SMTP relay endpoint. Point it at Postmark, Mailgun, AWS SES, or whatever you’re using for legitimate outbound. Plan for about $1-2/month for light usage on most providers.
Initialize and Run
docker compose up -d postgres redis# Wait a few seconds for postgres to initializedocker compose run --rm app flask db upgradedocker compose up -dPoint your reverse proxy (Caddy, Nginx, Traefik) at port 7777 for the web UI. Make sure your MX record’s port 25 reaches the email-handler container on port 20381 — most reverse proxies don’t handle SMTP, so you’ll need to forward port 25 → 20381 directly at the host level or via your firewall.
# On the host, if using ufw or iptables:iptables -t nat -A PREROUTING -p tcp --dport 25 -j REDIRECT --to-port 20381Or just expose port 25 in Docker and map it to 20381 in the compose file if SimpleLogin is the only mail service on the host.
Self-Hosting addy.io
Compose Setup
services: addy: image: anonaddy/anonaddy:latest restart: unless-stopped depends_on: - postgres env_file: - .env ports: - "8080:8080" volumes: - ./storage:/var/www/html/storage
addy-worker: image: anonaddy/anonaddy:latest restart: unless-stopped command: ["php", "artisan", "queue:work", "--tries=3"] depends_on: - postgres env_file: - .env
postgres: image: postgres:15-alpine restart: unless-stopped environment: POSTGRES_USER: addy POSTGRES_PASSWORD: changeme POSTGRES_DB: addy volumes: - ./postgres-data:/var/lib/postgresql/dataaddy.io Environment
APP_NAME=addyAPP_ENV=productionAPP_KEY=base64:your_generated_key_hereAPP_URL=https://addy.yourdomain.com
DB_CONNECTION=pgsqlDB_HOST=postgresDB_PORT=5432DB_DATABASE=addyDB_USERNAME=addyDB_PASSWORD=changeme
# Mail receivingANONADDY_DOMAIN=yourdomain.comANONADDY_HOSTNAME=mail.yourdomain.com
# Outbound SMTP relayMAIL_MAILER=smtpMAIL_HOST=smtp.postmarkapp.comMAIL_PORT=587MAIL_USERNAME=your-postmark-tokenMAIL_PASSWORD=your-postmark-tokenMAIL_ENCRYPTION=tlsMAIL_FROM_ADDRESS=[email protected]
# Limits (generous for self-hosted)ANONADDY_BANDWIDTH_LIMIT=10GBANONADDY_ALIAS_LIMIT=0DNS setup for addy.io is identical to SimpleLogin — same MX, SPF, DKIM, DMARC structure. addy.io uses Laravel’s key generation:
docker compose run --rm addy php artisan key:generatedocker compose run --rm addy php artisan migrate --forcedocker compose up -dAdding Your Custom Domain in addy.io
Once the app is running, log in, go to Domains, add yourdomain.com. addy.io will show you the exact DNS records it needs and verify them. This is where you set up the catch-all behavior: any address *@yourdomain.com routes through addy’s alias table and forwards to your registered inbox.
Replying Through Your Alias
This is the feature that makes the whole thing actually usable. Without it, you could receive mail through an alias but you’d have to reply from your real address, instantly exposing it.
Both SimpleLogin and addy.io handle this with a header-rewriting trick. When a forwarded email arrives in your real inbox, the Reply-To header is set to a special bounce address on your aliasing server (something like [email protected]). When you reply, your real mail client sends to that address. The aliasing server receives it, decodes the original sender, rewrites the From header to your alias, and delivers the reply through your SMTP relay.
From the recipient’s side: they see a reply from [email protected]. Your Gmail address is never in the headers. It’s not magic; it’s just header manipulation. But it works.
Threat Model: When Does Aliasing Actually Help?
Aliasing is good at one specific thing: isolating your real email address from third parties you don’t fully trust.
- Data breach containment — When
shady-app.iogets breached, they have[email protected], not your real address. Disable the alias, move on. - Spam source identification — Each signup uses a unique alias. When spam starts arriving, you know exactly who sold you out.
- Domain portability — Your aliases travel with your domain. Switch your real inbox from Gmail to Fastmail? Update one forwarding setting in SimpleLogin. No one you’ve given addresses to needs to know.
Aliasing is not a full anonymity solution. Your aliasing server knows your real address. If someone gets access to it, they see everything. And metadata — timing, volume, IP in the received headers — can still leak information even when the address itself is hidden.
If your threat model involves “keep my email private from sophisticated adversaries with legal authority,” you need Tor-accessed Proton with no recovery options, not a self-hosted forwarder. But for “I don’t want Booking.com knowing my real address” — aliasing is exactly right.
The Backup Problem (And Why It Matters More Than You Think)
Here’s the failure mode nobody talks about when they’re setting up a cool self-hosted aliasing server: your server dies.
If you’re using hosted SimpleLogin via Proton ($4/month or free with a Proton plan), your aliases survive because they’re on Proton’s infrastructure. If you’re self-hosting and your VPS gets the boot, your database is unrecoverable, or you forget to renew your domain — every alias you’ve ever given out stops working simultaneously.
You’ve just effectively deleted your email address for every account that uses those aliases.
The mitigation:
- Daily database backups —
pg_dumpto a separate location. Not the same server. Not the same VPS provider. - Export your alias list — Both SimpleLogin and addy.io let you export a CSV of all aliases and their destinations. Keep a copy somewhere safe.
- Document your DNS config — When you need to rebuild, you want to know exactly which records go where.
# SimpleLogin: backup postgresdocker compose exec postgres pg_dump -U simplelogin simplelogin | gzip > /backup/sl-$(date +%Y%m%d).sql.gz
# addy.io: backup postgresdocker compose exec postgres pg_dump -U addy addy | gzip > /backup/addy-$(date +%Y%m%d).sql.gzSchedule that. Automate it. Test your restore process at least once. Your 2 AM self who just lost their VPS will appreciate it.
Alternatively: if reliability matters more than control, just pay Proton for hosted SimpleLogin and skip the ops burden. Four dollars a month buys you someone else’s uptime guarantee and a team of people who care about DKIM alignment more than you want to.
Should You Bother?
Yes, if:
- You sign up for a lot of services and hate email clutter / breach exposure
- You already have a domain you own and some VPS budget
- You’re comfortable with basic Docker ops and DNS management
- You want the alias to match your domain, not
[email protected]
Probably not if:
- You’re looking at this as a way to avoid using Proton’s hosted SimpleLogin to save $4/month — the ops cost isn’t worth it unless you genuinely enjoy the setup
- You need it to be bulletproof without any maintenance — hosted is more reliable
- You’re hoping this replaces a full email server — it doesn’t. You still need a real inbox somewhere
The honest take: aliasing on your own domain is one of the most practical privacy tools available to a home lab person. It’s not glamorous, it doesn’t require explaining threat models to normies, and it just works once it’s set up. SimpleLogin and addy.io are both solid choices. The difference is whether you care more about polish and apps (SimpleLogin) or pure open-source independence (addy.io).
Pick one, set it up on a Saturday afternoon, and next time some website requires your email to download a whitepaper, give them [email protected]. When the spam starts, you’ll know exactly who to blame — and you’ll be one click away from making it stop.