Mailbox migration: docker-mailserver → Stalwart
Tools to move accounts, aliases, and mail from a docker-mailserver instance into
this Stalwart deployment.
Overview
| Step | Linux (bash) | Windows (PowerShell) | Purpose |
|---|---|---|---|
| 1 | export-docker-mailserver.sh |
(run on the Linux docker-mailserver host) | Dumps accounts + aliases from docker-mailserver's config files into accounts.csv |
| 2 | (manual) | (manual) | Fill in new_password (and old_password if not already known) in accounts.csv |
| 3 | generate-account-plan.sh |
New-AccountPlan.ps1 |
Turns accounts.csv into a stalwart-cli apply NDJSON plan that creates the domain, accounts, and aliases in Stalwart |
| 4 | stalwart-cli apply |
stalwart-cli apply |
Applies the generated plan to Stalwart |
| 5 | sync-mailboxes.sh |
Sync-Mailboxes.ps1 |
Runs imapsync (via Docker) for every account, copying all folders/messages from docker-mailserver to Stalwart |
| 6 | (manual) | (manual) | Verify, then repoint MX/DNS and decommission docker-mailserver |
Both old and new mail servers run Linux, so the bash scripts are the primary path;
the PowerShell scripts are equivalent for driving the migration from a Windows
workstation. Make the bash scripts executable once: chmod +x migration/*.sh.
generate-account-plan.sh requires jq (apt install jq / dnf install jq).
docker-mailserver stores passwords as one-way hashes (config/postfix-accounts.cf),
so they cannot be reused directly in Stalwart. Each account gets a new password
during migration; old_password is only needed temporarily so imapsync can log in
to the source server to copy mail.
1. Export accounts and aliases from docker-mailserver
Run on the docker-mailserver host (or docker exec into its container), pointing at
its config directory:
./export-docker-mailserver.sh /path/to/docker-mailserver/config > accounts.csv
This produces accounts.csv with columns email,new_password,old_password,aliases,quota_mb,
new_password and old_password left blank for you to fill in.
2. Fill in passwords
Edit accounts.csv:
new_password: the password the account will have on Stalwart. Generate strong random values; users can change them later via the WebUI.old_password: the account's current, plaintext docker-mailserver password, needed only soimapsynccan authenticate to the source during copy. If you don't have it, reset it temporarily on docker-mailserver withsetup email update <email> <temp-password>and record that value here.aliases: optional,;-separated list of extra local-parts on the same domain that should deliver to this mailbox (e.g.info;sales).quota_mb: optional mailbox quota in MB (blank = unlimited).
Never commit a filled-in accounts.csv; it contains plaintext passwords.
3. Generate the Stalwart account plan
Linux:
./generate-account-plan.sh -c accounts.csv -d eternityproject.fi -o accounts-plan.ndjson
Windows:
./New-AccountPlan.ps1 -CsvPath accounts.csv -Domain eternityproject.fi -OutFile accounts-plan.ndjson
This upserts the Domain, one Account/User per row (with a Password credential
set to new_password and any aliases), so re-running after edits is safe.
4. Apply the plan to Stalwart
Linux:
export STALWART_URL="https://mail.eternityproject.fi"
export STALWART_USER="admin"
export STALWART_PASSWORD="<admin password>"
stalwart-cli apply --file accounts-plan.ndjson --dry-run
stalwart-cli apply --file accounts-plan.ndjson
Windows:
$env:STALWART_URL = "https://mail.eternityproject.fi"
$env:STALWART_USER = "admin"
$env:STALWART_PASSWORD = "<admin password>"
stalwart-cli apply --file accounts-plan.ndjson --dry-run
stalwart-cli apply --file accounts-plan.ndjson
5. Copy mail with imapsync
Linux:
./sync-mailboxes.sh -c accounts.csv -s mail.old-domain.example -t mail.eternityproject.fi -n
Windows:
./Sync-Mailboxes.ps1 `
-CsvPath accounts.csv `
-SourceHost mail.old-domain.example `
-DestHost mail.eternityproject.fi `
-DryRun
(-n / -DryRun runs imapsync in dry-run mode first; drop it to actually copy messages.)
Review the dry-run output, then re-run without -DryRun to actually copy messages.
The script is safe to re-run: imapsync skips messages that already exist at the
destination.
6. Cut over
- Spot-check folder counts/message counts on a few mailboxes in the Stalwart WebUI.
- Run
Sync-Mailboxes.ps1once more shortly before cutover to catch mail received during the migration window. - Update MX records to point at
mail.eternityproject.fi(see the top-level README.md). - Once confirmed, decommission docker-mailserver and rotate the temporary
old_passwordvalues you set in step 2.