Migrate Off Gmail: A Practical Guide for Devs to Host Your Own Email
emailself-hostingmigration

Migrate Off Gmail: A Practical Guide for Devs to Host Your Own Email

ssolitary
2026-01-21 12:00:00
12 min read
Advertisement

Practical, dev-focused steps to migrate from Gmail to a self-hosted mail stack with Postfix/Dovecot or Mailcow — DNS, DKIM/DMARC/SPF, backups, and CI.

Stop trusting your inbox to somebody else — practical steps to run your own mail in 2026

If you’re a developer or sysadmin who’s uncomfortable with vendor lock-in, recent changes to Gmail’s data policies, and the idea of an AI platform indexing your personal mail, you’re not alone. In 2026 the conversation has shifted from “can I self-host?” to “how do I realistically migrate my day-to-day email from Gmail to a private, maintainable stack?” This guide gives a pragmatic, step-by-step migration path: plan, provision, install Postfix/Dovecot or Mailcow, configure SPF/DKIM/DMARC, migrate messages, automate configuration with CI, and set up reliable backups and monitoring.

Quick roadmap (what you’ll accomplish)

  • Design a migration plan and choose between a managed mail suite (Mailcow) or a custom Postfix+Dovecot build.
  • Provision a VPS with proper DNS (PTR, MX) and set up TLS via Let’s Encrypt.
  • Publish SPF, generate DKIM keys, create DMARC and MTA-STS records.
  • Migrate mail and contacts using imapsync or Google Takeout → mbox import.
  • Implement encrypted backups (Borg/Restic) and mailbox-level sync (doveadm dsync).
  • Deploy CI to test and apply config changes reliably (Git + GitHub Actions / self-hosted runner + Ansible).

Context: why self-host in 2026?

Late 2025 and early 2026 saw large email providers accelerating AI integration and new policy decisions that push users to re-evaluate centralised mail providers. If privacy, control and predictable costs matter to you — especially for small teams — self-hosting offers a realistic alternative. Modern tooling (containerized stacks, ACME automation, and mature deliverability standards) makes a robust private mail server feasible for technical users.

Before you start: checklist

  1. Domain ownership and control of DNS (must be able to add TXT, MX, CNAME).
  2. VPS with a static IPv4 (and IPv6 if possible) where you can set a PTR record matching your mail hostname.
  3. Plan an email address change policy and aliasing strategy (keep old Gmail as forwarding/backup while migrating).
  4. Decide: Mailcow (recommended for fast, production-ready) or a hand-built Postfix + Dovecot + OpenDKIM stack.
  5. Back up Gmail first (Google Takeout) — never assume rollback won’t be needed.

Step 1 — Provisioning and networking

Choose a provider that allows clean IPs and reverse DNS. Many consumer clouds now block outbound port 25 by default — pick a host that explicitly permits SMTP or offers a dedicated IP. Use a small VM (2 vCPU / 4–8 GB RAM) to start for personal/small-team email.

Example network checklist:

  • Hostname: mail.example.com (A/AAAA records)
  • PTR record: set at your VPS provider to mail.example.com
  • Firewall: allow ports 25 (SMTP), 587 (submission), 465 (SMTPS optional), 143/993 (IMAP/IMAPS), 110/995 (POP if needed), 443 (web UI)
  • Ensure IPv6 PTR if you publish an IPv6 address

Step 2 — Choose your stack: Mailcow vs. DIY Postfix+Dovecot

Both approaches are valid. Mailcow (dockerized) bundles Postfix, Dovecot, Rspamd, LetsEncrypt integration, a web UI, admin flows, and DKIM signing — that makes delivery and maintenance easier. The DIY route gives more control for unique requirements.

Mailcow (fast, opinionated, widely used)

Install steps (Ubuntu/Debian VPS):

git clone https://github.com/mailcow/mailcow-dockerized.git
cd mailcow-dockerized
cp .env.example .env
# edit .env and set MAILCOW_HOSTNAME=mail.example.com and the mail domain(s)
./generate_config.sh
docker compose pull
docker compose up -d

Mailcow handles DKIM and Let’s Encrypt for you (ACME), and exposes a web admin UI at https://mail.example.com with a default admin created during config. Follow the Mailcow docs to secure the admin account and configure fail2ban and rate-limiting.

DIY Postfix + Dovecot (full control)

Install base packages (Ubuntu example):

apt update && apt install -y postfix dovecot-core dovecot-imapd opendkim opendkim-tools certbot

Key items to configure:

  • Postfix main.cf: myhostname, myorigin, mynetworks, inet_interfaces, smtpd_tls_security_level, smtpd_relay_restrictions
  • Dovecot: mail_location (maildir:/var/mail/vhosts/%d/%n), auth backend (passwd-file, SQL, or LDAP), SSL certs path
  • OpenDKIM: Key table and signing table; integrate with Postfix using milter

Step 3 — TLS: Let’s Encrypt (ACME)

Proper TLS is essential: for submission (587), for IMAPS, and for SMTP TLS. Mailcow automates ACME. For DIY, use certbot or acme.sh.

# certbot (webroot or DNS-01 for wildcard)
apt install certbot
certbot certonly --standalone -d mail.example.com -m admin@example.com --agree-tos --non-interactive

If you host multiple domains or need wildcard certificates, use DNS-01 with your DNS provider’s plugin.

Step 4 — DNS records: MX, SPF, DKIM, DMARC, MTA-STS, TLS-RPT

Deliverability is won or lost at DNS. Start with permissive policies, verify sending, then tighten.

MX

example.com.  IN MX 10 mail.example.com.

SPF (start permissive then tighten)

Example transitional SPF (you might still want Gmail during migration):

example.com. IN TXT "v=spf1 mx ip4:203.0.113.45 include:_spf.google.com -all"

After migration, remove the Google include and only publish the IPs or your MX host names.

DKIM

For DIY OpenDKIM, generate a key and add the public key as a TXT record under a selector (e.g., mail._domainkey.example.com):

opendkim-genkey -s mail -d example.com
# This produces mail.private and mail.txt
# Add the content of mail.txt as a TXT record at mail._domainkey.example.com

Mailcow automatically creates DKIM selectors and displays the DNS records in the UI.

DMARC

Start with reporting only and inspect for 2–4 weeks:

_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc-aggregate@example.com; ruf=mailto:dmarc-forensics@example.com; pct=100; fo=1"

MTA-STS ensures strict TLS for SMTP peers and is increasingly required by big providers. Publish the policy as a small HTTPS-served file on a domain like mta-sts.example.com and a TXT record at _mta-sts.example.com.

Example TLS-RPT TXT: v=TLSRPTv1; rua=mailto:tlsrpt@example.com. Set up an HTTP endpoint serving your MTA-STS policy.

Step 5 — Migrating mail and contacts

Two practical migration routes: live IMAP synchronization with imapsync, or export via Google Takeout and import offline.

imapsync copies mail from the old IMAP server (Gmail) to your new IMAP server. Be conscious of Google’s authentication rules: in 2026 you may need an OAuth2 token or an App Password depending on your account type. imapsync supports OAuth2; see imapsync docs for setup.

imapsync \
  --host1 imap.gmail.com --user1 you@gmail.com --password1 'APP-PASSWORD-OR-OAUTH-TOKEN' \
  --host2 mail.example.com --user2 you@example.com --password2 'YOUR-NEW-IMAP-PASS' \
  --syncinternaldates --delete2duplicates --exclude "^Spam$"

Run with --dry first to simulate. Use folder mapping to convert Gmail labels to IMAP folders if needed.

Option B: Google Takeout -> MBOX -> Dovecot

If OAuth syncing is problematic, export mail with Google Takeout (MBOX). Then convert MBOX to Maildir and inject into Dovecot maildirs using utilities like mb2md or mbox2maildir, or use offline IMAP tools like isync/mbsync to push mail into the server.

# Example: using mbsync to push local mbox to remote
# configure mbsync with source pointing to local mbox and target to your new IMAP account
mbsync -c ~/.mbsyncrc --syncall newaccount

Don’t forget to export contacts (vCard) and calendars (ICS) from Google and import them into your new CardDAV/CalDAV service (e.g., Baïkal, Nextcloud, or Mailcow’s integrated groupware).

Step 6 — Backups and restores (non-negotiable)

Backups must be encrypted, test-restorable, and scheduled. Use mailbox-aware tools when possible to preserve flags and UIDs.

Approach A: Maildir-level backups with Borg

# initialize repo (remote or local)
borg init --encryption=repokey /var/backups/borg/mail-repo
# create a snapshot
borg create --stats /var/backups/borg/mail-repo::$(date +%F) /var/vmail
# prune old snapshots
borg prune -v --keep-daily=7 --keep-weekly=4 --keep-monthly=6 /var/backups/borg/mail-repo

Secure the repo with a passphrase stored in an HSM or secret manager. Schedule with systemd timers.

Approach B: Dovecot dsync for mailbox-level replication

# replicate mailbox from primary to backup server (doveadm)
doveadm -Dv sync -u user@example.com ssh:user@backup 'doveadm sync -u user@example.com mbox:/var/mail/vhosts/example.com/'

dsync allows incremental sync and UID preservation, useful when you need point-in-time recoveries.

Back up configuration and TLS

  • Git for configuration (Postfix/Dovecot/OpenDKIM), store secrets in a vault (HashiCorp Vault or Sealed Secrets).
  • Back up Mailcow’s docker volumes via scheduled archive jobs and push to remote blob storage.

Step 7 — CI for mail config: GitOps approach

Treat mailserver configuration as code. Keep Postfix/Dovecot/OpenDKIM templates and Ansible playbooks in a Git repo. Use CI to validate and deploy.

Example CI flow (GitHub Actions)

  1. On PR: lint configs (postconf -n, dovecot -n, opendkim-testkey)
  2. Spin a disposable container to smoke-test (optional)
  3. On merge to main: deploy to staging via Ansible, run acceptance tests (SMTP connect, DKIM sign/verify, IMAP login)
  4. If staging green: deploy to production with a controlled maintenance window

Example action step (pseudo):

name: CI Deploy Mail
on: [push]
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Lint Postfix
        run: postconf -n -c ./configs/postfix || exit 1
      - name: Lint Dovecot
        run: dovecot -n -c ./configs/dovecot || exit 1
  deploy:
    needs: lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to host
        uses: appleboy/ssh-action@v0.1.8
        with:
          host: ${{ secrets.MAIL_HOST }}
          username: ubuntu
          key: ${{ secrets.SSH_KEY }}
          script: |
            cd /srv/mail-config && git pull
            ansible-playbook -i inventory/hosts site.yml --limit mailserver

Keep secrets out of Git and use environment secrets or a vault. Add automated tests to verify DKIM signing and DMARC aggregate parsing after any change.

Step 8 — Monitoring, testing, and tightening

After you’re sending, watch real traffic and DMARC reports for at least 2–4 weeks. Run deliverability tests (mail-tester, MXToolbox), and monitor logs for bounces, blacklisting, or spam traps.

  • Set DMARC to p=none initially; move to p=quarantine and then p=reject once you’re confident.
  • Enable and monitor MTA-STS and TLS-RPT (see regulatory guidance on policy records).
  • Implement fail2ban and Rspamd (Mailcow includes Rspamd) to throttle abuse.

Troubleshooting: common gotchas

  • ISP or cloud blocking port 25 — request removal or use a relay temporarily.
  • IP reputation: new IPs may have low reputation; warm-up before high-volume sending.
  • PTR mismatch: set reverse DNS to your mail hostname — otherwise many providers will mark mail as suspicious.
  • Incorrect DKIM TXT syntax: long keys must be on one line in DNS providers that don’t support multiline entries.
  • Gmail OAuth rules: when using imapsync against Gmail, configure OAuth or use an app-specific token and enable IMAP access.

Security and privacy best practices

  • Enable 2FA on any admin UI and restrict access via VPN or allowlist IPs.
  • Encrypt backups with strong keys and rotate periodically.
  • Consider end-to-end encryption (OpenPGP, S/MIME) for highly sensitive mail workflows.
  • Log retention: keep logs long enough for audit, but delete PII where possible — document your retention policy.

Real-world example: small consultancy migration (summary)

We migrated a 6-person consultancy in 2025 using Mailcow on a single VPS. Steps we took:

  1. Exported all mail via imapsync over two weekends (initial bulk + incremental sync on cutover day).
  2. Kept the Gmail alias active for 30 days with forwarding and a final bounce policy.
  3. Published SPF that temporarily included Gmail, then removed it after we confirmed no outgoing Gmail remains.
  4. Used Borg to snapshot /var/vmail nightly and store encrypted archives in a remote S3 bucket (server-side encrypted) and weekly restores to verify integrity.
  5. Used GitOps for configuration and a GitHub Action to test configs before applying them, which caught a DKIM key mismatch before deployment.

Result: full control of mail, predictable VPS costs, and no third-party AI indexation of private mailboxes.

What to expect in 2026 and next steps

"Expect stricter envelope-level TLS enforcement, wider adoption of MTA-STS/TLS-RPT, and continuing pressure from large providers to enforce DMARC policies. Plan for shorter key rotations and automated tooling for privacy-first operations."

In 2026, expect major providers to tighten delivery rules further and to favor authenticated, well-configured senders. Running your own mailserver means you must keep up with these standards — but automation and containerized stacks make maintenance far easier than years ago.

Actionable takeaways

  • Do a full Google Takeout now — keep a local MBOX copy before making changes.
  • Prefer Mailcow if you want a fast, supported path with fewer surprises.
  • Publish SPF, DKIM, DMARC (start permissive), then tighten after monitoring reports.
  • Automate configuration with Git + CI; do not edit production configs manually.
  • Implement encrypted, tested backups and periodic restore rehearsals.

Final checklist before cutting over

  • DNS (MX, SPF, DKIM, DMARC) published and propagated
  • TLS certificate valid for mail.example.com
  • IMAP login works for all users
  • imapsync completed an incremental run and you validated message counts
  • Backups scheduled and tested (restore at least one mailbox)
  • Monitoring in place (DMARC aggregate, TLS-RPT, log alerting)

Next step — start your migration

Ready to try it? Spin up a test VM, follow the Mailcow quick install above, perform an imapsync dry run, and beef up your backups. If you want a jump start, fork a Git repo with an Ansible playbook for Postfix/Dovecot, add your DNS records, and wire a GitHub Action to deploy to your test host. Keep the old Gmail active and forward or alias mail for at least 30 days during the cutover.

If you want a reproducible starting point, we maintain a reference repo and CI templates for Mailcow and Postfix/Dovecot (with Borg backups and GitOps deployment). Clone it, adapt it to your domain, and begin your migration in a dedicated staging environment.

Call to action

Take control of your email in 2026: export your Gmail today, run a test Mailcow install, and schedule an imapsync. If you want a curated starting kit (Ansible playbook, GitHub Actions pipeline, Borg backup templates), clone our repository and follow the README to run a full dry-run migration in under a day.

Advertisement

Related Topics

#email#self-hosting#migration
s

solitary

Contributor

Senior editor and content strategist. Writing about technology, design, and the future of digital media. Follow along for deep dives into the industry's moving parts.

Advertisement
2026-01-24T04:14:50.400Z