Skip to content

guides

Email migration with two-way sync: run Tinbox alongside an existing mailbox

May 24, 2026

#email-migration#two-way-sync#imap#gradual-migration#data-ownership
Email migration with two-way sync: run Tinbox alongside an existing mailbox
Visual: Greta Impressa on okslop

Cutting over email in one switch is terrifying, so most people never start. The fix is to stop treating migration as a switch and start treating it as an overlap you can roll back at any point.

The reason email migrations stall is not technical difficulty. It is that the failure mode is silent and expensive: if you flip MX and something is wrong, mail bounces or vanishes and you find out from an angry customer, not a monitoring alert. So the project sits in the backlog forever. The way out is to make the migration reversible at every step by running the new system alongside the old one, sending nothing through it until you trust it, and keeping the old mailbox authoritative the whole time. This guide walks that overlap strategy honestly, including the part most "two-way sync" pitches skip: real bidirectional sync is hard, and you usually do not want it.

Can you run two email systems at the same time during a migration?

Yes, and it is the safest way to migrate. You dual-deliver new inbound mail to both the old and new systems while periodically mirroring the old mailbox into the new one over IMAP, and you keep the old account authoritative until you have proven the new one. The new system is read-only-ish during this phase: it receives copies and shows history, but your real mailbox is untouched, so the worst outcome is duplicate mail rather than lost mail.

This works because the three jobs in any email migration are independent and you can sequence them with long gaps:

  1. Inbound copy. Get new mail flowing to the new system without taking it away from the old one. This is forwarding or a catch-all copy, and it changes nothing about your existing setup.
  2. History backfill. Pull the existing years of mail into the new system over IMAP. This is slow and bandwidth-bound, so it runs in the background across days.
  3. Authoritative cutover. The single moment that actually moves inbound delivery (MX) and outbound trust (SPF/DKIM/DMARC). Everything before this is reversible by deleting the new system and walking away.

The mistake that loses mail is collapsing these into one event. Keep them separate and the only irreversible step is the last one, which you do only after weeks of evidence. Collapsing the phases is far from the only way a move goes wrong; the migration mistakes that tank deliverability catalogs the rest, and the provider switch checklist sequences the whole cutover step by step.

What is two-way email sync, and do you actually want it?

Two-way (bidirectional) sync means changes on either mailbox propagate to the other: a message you read, move, flag, or reply to on one side shows up the same way on the other. It sounds like the ideal migration bridge. In practice it is the part to be most careful about, because IMAP was not designed for it and the edges are sharp.

The honest problems with true two-way sync:

  • UIDs are not portable. IMAP message UIDs are per-mailbox and per-server. A sync engine has to fingerprint messages (Message-ID, headers, body hash) to match them across servers, and fingerprinting has false matches and misses.
  • Flag conflicts. If a message is marked read on one side and unread on the other, which wins? There is no universal answer, and naive engines flap state back and forth.
  • Loops and duplicates. Forwarding into a mailbox that also syncs back can re-import its own forwards. Without careful de-duplication you get geometric duplicate growth.
  • Reply attribution. If you reply from both accounts during the overlap, threads fork. Recipients see two different From addresses on the same conversation.

So the practical answer for a migration is: do not run a permanent bidirectional bridge. Run a one-way mirror (old to new) for history, plus dual-delivery for new inbound mail, and pick exactly one account to reply from at a time. That gives you everything the scary "two-way sync" promise was for (the new system reflects your real mail) without the conflict surface. Reserve genuine bidirectional sync for a short, supervised window if you truly need both sides live, and expect to clean up duplicates afterward.

How do I set up dual-delivery so new mail lands in both mailboxes?

Forward a copy of every inbound message from the old mailbox to the new one, or, if you control the domain's routing, add a rule that copies inbound mail to a second destination. The old mailbox stays the real one; the new mailbox gets a live feed.

The simplest version, on Gmail or Google Workspace, is a forwarding rule. In Gmail: Settings → Forwarding and POP/IMAP → add a forwarding address pointing at the new system's ingest address, verify it, then create a filter that matches everything and applies "Forward to" without deleting:

Filter: Matches: has:nouserspecified  (i.e. "all mail")
Action: Forward to new-stack@yourdomain.tld
        (leave "Skip the Inbox" unchecked so Gmail stays authoritative)

This is enough to start evaluating the new system against live mail today, with zero risk. The catch with Gmail forwarding is that it forwards only mail that lands in the inbox, so spam-foldered mail and some filtered mail will not forward. That is acceptable during evaluation (you are testing the new system, not relying on it), and it is moot after the real MX cutover.

If you run your own inbound routing, dual-delivery is cleaner because you copy at the routing layer before any filtering. On Cloudflare Email Routing, for example, a catch-all can forward to a Worker, and the Worker can both store the message and forward a copy onward. See setting up MX records for a Cloudflare inbox for the routing side of this.

How do I backfill years of history with a one-way IMAP mirror?

Run imapsync (or offlineimap) from the old mailbox into the new one, one direction only, and re-run it periodically so the new system stays current until cutover. One-way means old-to-new: you never write back to the source, which removes the entire conflict class above.

Enable IMAP and create an app password on the source account first (Gmail requires 2FA to create one). Then:

imapsync \
  --host1 imap.gmail.com --port1 993 --ssl1 \
  --user1 jane@yourdomain.tld --password1 "SOURCE_APP_PASSWORD" \
  --host2 imap.new-stack.yourdomain.tld --port2 993 --ssl2 \
  --user2 jane@yourdomain.tld --password2 "DEST_PASSWORD" \
  --no-modulesregex --useuid --skipcrossduplicates

The flags matter for an overlap migration:

  • --useuid matches messages by UID where possible and falls back to header fingerprinting, which keeps re-runs incremental instead of re-copying everything.
  • --skipcrossduplicates avoids importing the same message twice when it exists in multiple source folders (common with Gmail labels, which IMAP exposes as folders).
  • One direction only: there is no imapsync reverse pass. The new system is a mirror, not a peer.

A common failure on the first run looks like this:

Host2 failure: Error login on [imap.new-stack.yourdomain.tld] with user [jane] auth [LOGIN]:
2 NO [AUTHENTICATIONFAILED] Invalid credentials

That is almost always the destination requiring an app-specific password or an explicit IMAP-enabled flag, not your real account password. Fix it by issuing a dedicated import credential on the destination and re-running; imapsync resumes where it left off because it tracks what it has already copied. Re-run the same command on a schedule (a nightly cron is plenty) so the mirror tracks the source until the day you cut over. The detailed mechanics live in importing an IMAP mailbox into a self-hosted stack.

What is the right order to cut over without losing mail?

Lower the MX TTL a day ahead, repoint MX to the new host, immediately run one final IMAP delta sync, then move SPF/DKIM/DMARC and stop forwarding. The order exists to shrink the only irreversible window to a few minutes.

Walking it precisely:

  1. The day before: drop the MX record TTL to 300 seconds. This does not change where mail goes; it just makes the next change propagate in minutes instead of hours. Run a normal mirror sync so the new system is current.
  2. Cutover: change the MX records to point at the new host. New inbound mail now lands at the new system as the primary, not a copy.
  3. Immediately after: run one final imapsync delta. During DNS propagation a handful of messages may still hit the old mailbox; this final pass pulls them into the new system. This is the step people skip, and it is exactly where the "I lost mail during migration" stories come from.
  4. Authentication: update SPF to authorize the new sender, publish the new DKIM public key, and confirm DMARC still aligns before you send volume. Outbound trust is the silent failure mode: get it wrong and your sent mail goes to spam without bouncing. Setting up SPF, DKIM, and DMARC and the email deliverability guide cover this in depth.
  5. Stop forwarding and decommission. Remove the dual-delivery rule, verify a full day of clean inbound delivery, then cancel the old seats. Keep the old subscription active until this is verified so you retain a rollback path.

Note that you do not move SPF/DKIM/DMARC during the overlap. While you are dual-delivering and still replying from the old account, your old account is still the legitimate sender, so leave its authentication intact. Move outbound trust only when outbound actually moves.

What does the overlap cost, and how long should it run?

Run both systems in parallel for one to four weeks, and budget the cost of one duplicate-mail stream plus the old subscription fee. There is deliberately no rush, because the entire point of the overlap is to buy confidence with time rather than with a stressful big-bang.

During the overlap, watch four things:

  • Completeness: is anything inbound being dropped or filtered out before it reaches the new system? Compare counts between old and new daily.
  • Search and triage quality: does the new system find old threads and classify new ones the way you need? This is where full-text search and inbound classification earn their keep.
  • Deliverability of replies: if you reply from the new account at all during overlap, confirm those land in the recipient's inbox, not spam.
  • Duplicates: confirm de-duplication is holding and the mirror is not re-importing forwards.

When a full week passes with none of these throwing a surprise, cut over. If something does surprise you, you delete the new system and you have lost nothing but time, which is the whole reason to migrate this way.

How does Tinbox fit a phased, run-alongside cutover?

Everything above works with open tools and no vendor, which is the point: the migration mechanics do not depend on where you land. Where a self-contained stack like Tinbox changes the math is the cost and ownership of the "alongside" phase. The reason teams hesitate to run a second mailbox in parallel is that the destination is usually another paid mailbox per user, so the overlap doubles the bill and creates pressure to cut over before you are ready.

Tinbox is deployed onto your own Cloudflare account with npx tinbox init <domain>, so the destination during your overlap is infrastructure you already own (D1 for storage, R2 for attachments, Workers for ingest), not another per-seat subscription. That removes the financial pressure to rush the cutover. Concretely, it fits the phases like this:

  • Dual-delivery target. Point your Gmail forwarding rule (or your Cloudflare Email Routing catch-all) at the Tinbox ingest address. New mail starts flowing into a real inbox with full-text search and inbound classification immediately, while Gmail stays authoritative.
  • History backfill. Tinbox ships importers (Gmail, IMAP, mbox, Mailchimp) that fetch locally over a CLI and bulk-insert into your own D1, so the one-way mirror lands in storage you control. See the IMAP import walkthrough for the mechanics, and the ways to import old email into a self-hosted stack for the other source formats.
  • Evaluate with real tooling. Because the inbox is a database you own, you can run the AI chat agent and email interpreters over your real mail during the trial, which is exactly the kind of evaluation an overlap is for.
  • Cutover. When you trust it, repoint MX, run the final delta, move authentication, and stop forwarding. Nothing about that final step is Tinbox-specific.

Two honest caveats so you size this correctly. First, Tinbox does not do permanent bidirectional sync, and neither should your migration; it is built for the one-way-mirror-plus-dual-delivery pattern this guide recommends, with a hard MX cutover at the end. Second, a Tinbox deploy is one brand and domain per instance today (you run many tenants by deploying separately on the same Cloudflare account); multi-domain-per-instance is designed but not built, so plan one deploy per domain you are migrating.

If you want the broader version of this, the full Google Workspace email migration guide covers the team-wide case with multiple mailboxes, groups, and shared inboxes.

The takeaway is smaller than the project felt at the start: you never have to flip a switch you cannot un-flip. Run the new system alongside the old, mirror one direction, dual-deliver the new, and reduce the irreversible part to a five-minute MX change you have rehearsed.

Deploy this yourself: npx tinbox init <domain>, point a forwarding rule at it, and run the overlap as long as you like. The importer and MX docs cover the backfill and cutover steps end to end.

Frequently asked questions

Can you run two email systems at the same time during a migration?

Yes. The standard approach is to dual-deliver new inbound mail to both the old and new systems (via forwarding or a catch-all that copies), while you periodically mirror the old mailbox into the new one over IMAP to backfill history. You keep sending from the old account until you trust the new one, then flip MX and stop forwarding. This lets you evaluate the new stack against live mail without risking the cutover.

What is two-way email sync and is it actually safe?

Two-way (bidirectional) sync means changes on either mailbox propagate to the other: a message read, moved, or replied to on one side is reflected on the other. It is genuinely hard and prone to loops, duplicates, and flag conflicts, because IMAP flag state and message UIDs are not stable across servers. For migrations, prefer a one-way mirror (old to new) plus dual-delivery for new mail, and avoid replying from both sides during the overlap. Reserve true two-way sync for short windows, not as a permanent bridge.

How do I migrate email gradually instead of all at once?

Phase it. Phase 1: stand up the destination and dual-deliver new mail to it via forwarding, changing nothing about your real mailbox. Phase 2: backfill history with periodic one-way IMAP syncs. Phase 3: start reading and replying in the new system for low-stakes mail while the old one stays authoritative. Phase 4: lower MX TTL, repoint MX to the new host, run a final delta sync, then move SPF/DKIM/DMARC and stop forwarding.

Will I lose mail if I run a new mailbox alongside Gmail?

Not if you never make the new system the sole destination until you trust it. During the overlap, Gmail stays authoritative and reachable, so the worst case is duplicate mail, not lost mail. The only real risk window is the MX cutover itself, which you de-risk by lowering MX TTL a day ahead and running one final IMAP delta sync after MX has moved to catch anything that landed in Gmail during propagation.

How long should I run both mailboxes in parallel?

Long enough to trust the new system against your real mail volume, typically one to four weeks. The overlap costs you a little duplicate noise and the old subscription fee, so there is no rush. Watch deliverability, search quality, and whether anything inbound is being dropped or misclassified, then cut over once a full week passes with no surprises.