Building Blue Canoe · 9 of 19
Thirty Mailboxes, No Leap of Faith
How Blue Canoe reconciled a mailbox migration by account identity rather than reassuring totals.

This account was drafted on 19 August 2026. Operational states, versions and test results describe that period unless a later update is explicitly dated.
A mailbox migration can produce an impressive amount of reassuring output while still leaving one awkward question unanswered: did all of the mail actually arrive?
We had 15 domains, 30 mailboxes, 60 migration aliases and 62 alias targets to move into the new platform. ‘It seemed to run successfully’ was not going to be a useful acceptance criterion.
The migration needed to be repeatable, resumable and accountable down to the individual mailbox.
Prepare the destination first
Before moving production mail, the destination storage was built and proved on both mailbox nodes. Dovecot's expected mail location was checked, the new storage was mounted, and a write-to-new-drive test confirmed that messages were landing where the design said they should.
The source data also had to be treated as an input rather than folklore. Domains, users and aliases were imported from a defined dataset and counted. That produced a known population against which the later mailbox work could be reconciled.
These checks are not glamorous, but they remove an entire class of migration failure: successfully copying the right data into the wrong place, or successfully processing an incomplete list.
Prove one mailbox before proving thirty
We did not begin with a bulk run. Individual accounts were used to prove connectivity, authentication, TLS identity, folder discovery and the behaviour of the transfer tool.
One deliberately substantial test mailbox contained more than 12,000 messages spread across 11 folders. It was useful because it exercised something closer to real history than an empty test account could.
The recorded repeat of that mailbox transferred no additional messages. That was important evidence: rerunning a transfer did not mean blindly duplicating the mailbox.
Turn the manual proof into machinery
Once the individual path was understood, the migration script grew the controls needed for a production run: preflight, folder creation, transfer, mailbox listing, all-mailbox selection, limits, start points, run identifiers and resume behaviour.
Those switches were not added to make the command line look comprehensive. Each one answered an operational need. A limit allowed a small batch. A start point made controlled continuation possible. A stable run identifier tied repeated work to the same migration. Resume prevented completed accounts from becoming ambiguous work again.
The script could therefore support both careful testing and the final bulk operation without creating a separate, unproven migration pathway for production day.
The ledger was the acceptance evidence
Every bulk attempt wrote to a versioned ledger. Mailboxes moved through explicit states rather than disappearing into a terminal window.
Through 24 July, the versioned transfer ledger contained 33 started and 33 completed-pass entries. Three earlier attempts had exercised one mailbox; the 24 July run then covered all 30. Reconciled by mailbox identity, that was 30 unique accounts, each with a recorded passing completion, and no recorded failed completion in that ledger window.
That distinction is exactly why the ledger existed. Counting completed-attempt lines would have suggested 33 mailboxes. Counting the known mailbox identities proved that all 30 intended accounts had completed.
Completion should survive a second look
The full preflight passed for all 30 mailboxes. The bulk ledger accounted for all 30. Simple transfer reruns did not reveal a missing population waiting to be copied.
None of that makes migration risk disappear. It does make the residual risk visible and bounded. We knew which accounts existed, which had been attempted, which had passed and how to resume if a later run was interrupted.
The useful lesson was not specific to IMAP. A long operation should leave behind enough structured evidence that somebody can assess it later without relying on the operator's memory.
A migration is not complete because the command stopped running. It is complete when every intended item can be accounted for and the destination has been independently checked.