docs
Try the demo Get started
Esc
↑↓ moveEnter openEsc close

Install it · 7 of 7

Moving accounts with inbuxa-migrate

inbuxa-migrate moves an account into inbuxa from IMAP, JMAP, DAV, Maildir, Google Takeout or Exchange: mail, calendars, contacts, identities, Sieve scripts and files, through an archive file that is also a backup.

4 min read

On this page

inbuxa-migrate moves one account at a time into inbuxa: its mail, calendars, contacts, identities, Sieve scripts and files. It is a program of its own, and runs on any Linux machine that can reach both servers. Nothing is installed on either of them.

Where it fits:

  • Coming from another server: it does the work of parts 2 and 3, the mail and everything else, in place of imapsync and exported files. Deciding who people are (part 1) and the cutover (part 4) are the same either way.
  • Coming from Stalwart: copying the store moves the whole server at once, and stays the way to do that. Use inbuxa-migrate instead to move only some accounts, or into an inbuxa server that is already running.
  • As a backup: an account's archive can be filled on a schedule and written back later.

Install it

Linux, on amd64 or arm64. Each release carries one archive per architecture and a SHA256SUMS file:

base=https://git.coffeylabs.org/inbuxa/inbuxa-migrate/releases/latest/download
curl -fLO "$base/inbuxa-migrate-linux-amd64.tar.gz"
curl -fLO "$base/SHA256SUMS"
sha256sum --check --ignore-missing SHA256SUMS
tar -xzf inbuxa-migrate-linux-amd64.tar.gz
./inbuxa-migrate --version

On arm64, fetch inbuxa-migrate-linux-arm64.tar.gz instead. The binary is the whole program.

How it works

Three commands, and a file between them:

inbuxa-migrate import imap … alice.sqlite    # the old account into an archive
inbuxa-migrate inspect alice.sqlite          # what landed
inbuxa-migrate export … alice.sqlite         # the archive into inbuxa

The archive is one SQLite file holding one account. import fills it from the old server and export writes it into inbuxa. The two never talk to each other, only to the archive, so the old server can be gone before the new one exists.

Both commands pick up where they stopped. Run import again and it adds what arrived since; run export again and it brings inbuxa up to date, read and flagged state included. Every command takes --dry-run, which reports the plan and writes nothing.

Sources

Source What comes across
JMAP: inbuxa, Stalwart, or any JMAP server Everything the server offers: mail, calendars, contacts, identities, Sieve scripts and files
IMAP Mail, chosen by folder name or pattern
CalDAV, CardDAV Calendars and events, address books and contacts
WebDAV A plain file collection, as a file tree
ManageSieve Sieve scripts, with the active one marked
Maildir Mail, read from a local Maildir++ tree
Google Takeout The .mbox, .ics and .vcf files in an export
Exchange Server Mail, calendars and contacts, through EWS
Exchange Online Mail, calendars and contacts, through Microsoft Graph

For one account on a server with several of these, run one import per source into the same archive: IMAP for the mail, CalDAV for the calendars, and so on.

Scripts that came from Stalwart keep working: their vnd.stalwart.* extensions are renamed to inbuxa's on the way in.

One account, end to end

Passwords are asked for at a prompt. For a script, put them in INBUXA_MIGRATE_PASSWORD instead, never on the command line.

inbuxa-migrate import imap \
  --url imaps://old.example.com \
  --auth-basic alice@example.com \
  alice.sqlite

inbuxa-migrate inspect alice.sqlite

Then write it into inbuxa. The account has to exist there first, either made in the console or created by a directory on first use. A dry run first shows what would happen, and names anything the server would refuse, such as a message over its size limit:

inbuxa-migrate export \
  --url https://mail.example.net \
  --auth-basic 'alice@example.com%migrator@example.net' \
  --account-name alice@example.com \
  --dry-run \
  alice.sqlite

Run it again without --dry-run to write. The sign-in there is on Alice's behalf: the migrator account's role lets it act for anyone, so nobody hands over a password.

Signing in to inbuxa

inbuxa's JMAP takes a token, not a password, so the sign-in above is refused on a server as it ships. There are two ways to give export what it needs:

  • For the migration, let JMAP take passwords. Start the server with INBUXA_HTTP_BASIC_AUTH=all in its environment, as described for the server's environment, run the exports, then take the variable out and restart. This is the only way to sign in on someone else's behalf, and it is what the loop below assumes.
  • Or use the account's own API key, made in the console under the account's API keys, with --auth-bearer in place of --auth-basic. INBUXA_MIGRATE_TOKEN holds it for a script. The key only reaches its own account, so this suits a handful of people more than a whole server.

At cutover

Run import and then export again for each account after MX has moved. Only what changed comes across: new mail, changed flags, edited contacts and events. A day later, once more for stragglers.

Many accounts

The archive holds one account, so many accounts are a loop. With administrator sign-ins on both sides, no one's password is needed. On the inbuxa side that needs JMAP to take passwords while it runs:

read -rs -p 'Source admin password: ' SRC; echo
read -rs -p 'Migrator password: ' DST; echo
while read -r addr; do
  INBUXA_MIGRATE_PASSWORD="$SRC" inbuxa-migrate import imap \
    --url imaps://old.example.com --auth-basic "$addr*admin" "$addr.sqlite"
  INBUXA_MIGRATE_PASSWORD="$DST" inbuxa-migrate export \
    --url https://mail.example.net --auth-basic "$addr%migrator@example.net" \
    --account-name "$addr" "$addr.sqlite"
done < accounts.txt

$addr*admin is Dovecot's master-user form. A server that signs in for someone else only through a separate authorization name, as imapsync's --authuser1 does, needs each person's own password here, or imapsync as its page describes.

What it doesn't move

  • Accounts themselves. It writes into accounts that exist. Make them first, or let a directory create them.
  • Passwords. Those come with a directory, or are handed out new.
  • Server settings, spam training and sessions, as on Coming from another server.

Keep the archives safe

An archive holds a whole mailbox in the clear. It is created readable by its owner only, and inbuxa-migrate warns if an existing one isn't. Delete the archives once the move is done, unless you keep them as backups.

The full reference for every source and flag is in the usage guide.