A Dockerized tool for migrating mailboxes from any IMAP server to Google Workspace using imapsync and Google Service Account authentication.
[NOTE] This tool is an alternative to the official Google Data Migration Service. It is recommended to try the official tool first — use this if it fails or if you need more flexibility over the migration process (e.g., folder filtering, bandwidth throttling, or other imapsync options).
┌──────────────────┐ imapsync ┌──────────────────────┐
│ Source IMAP │ ───────────────────────▸ │ Google Workspace │
│ Server │ IMAP ◂─▸ IMAP │ (via XOAUTH2) │
│ (any provider) │ │ │
└──────────────────┘ └──────────────────────┘
▲ ▲
│ user/password auth │ OAuth2 token
│ │ (Service Account
│ │ impersonation)
└───────── migrate.py orchestrates ──────────────┘
reads users.csv
The script reads a CSV of user mappings, obtains an OAuth2 access token for each destination Google Workspace account via service account impersonation, and runs imapsync to transfer all emails.
- Docker and Docker Compose
- A Google Cloud Service Account with:
- Domain-wide delegation enabled
- The scope
https://mail.google.com/authorized in the Google Admin Console under Security → API Controls → Domain-wide Delegation - A downloaded JSON key file
- Source IMAP credentials (username + password) for each mailbox to migrate
git clone https://github.com/ESNGermany/mail-migration
cd mail-migrationPlace your Google Service Account JSON key file in the project root:
service-account.json
Copy the example .env file and set your source IMAP host:
cp .env.example .envEdit .env:
OLD_HOST=mail.example.com
MAX_WORKERS=5 # (optional, defaults to 1)Copy the example CSV and fill in your migration pairs:
cp users.csv.example users.csvEdit users.csv:
old_user,old_pass,new_google_user
john@old-domain.com,s3cretPass,john@new-domain.com
jane@old-domain.com,an0therPass,jane@new-domain.com| Column | Description |
|---|---|
old_user |
Email/username on the source IMAP server |
old_pass |
Password for the source account |
new_google_user |
Destination Google Workspace email address |
Run the migration with Docker Compose:
docker compose upThis will:
- Build the Docker image (based on
imapsyncv2.319 + Python) - Mount
users.csv,service-account.json, andlogs/into the container - Migrate users in parallel (controlled by
MAX_WORKERS, default 1) - Write logs to both the console and
logs/migration.log
imapsync is idempotent — running it again will only sync new or changed messages. This makes it safe to re-run after fixing errors or adding new users.
Migration logs are written to logs/migration.log and to stdout. Example output:
2026-02-12 12:48:53,408 - INFO - Reading users from CSV...
2026-02-12 12:48:53,412 - INFO - Starting migration: user@old-domain.com -> user@new-domain.com
2026-02-12 12:55:55,145 - INFO - SUCCESS: user@new-domain.com
Since this tool wraps imapsync, you can extend migrate.py to pass any imapsync option. Common additions:
| Option | Description |
|---|---|
--exclude 'Spam' |
Skip specific folders |
--maxbytespersecond 100000 |
Throttle bandwidth |
--dry |
Simulate without transferring |
--subfolder2 'Imported' |
Place all imported mail in a subfolder |
--addheader |
Add migration header to messages |
mail-migration/
├── migrate.py # Main migration script
├── Dockerfile # Docker image (imapsync + Python)
├── docker-compose.yml # Container orchestration
├── .env.example # Example environment config
├── users.csv.example # Example user mapping CSV
├── .gitignore # Excludes secrets and logs
└── logs/
└── migration.log # Migration output log
| Issue | Fix |
|---|---|
CSV file not found |
Ensure users.csv exists in the project root |
OLD_HOST environment variable not set |
Check your .env file |
imapsync auth failures on source |
Verify source credentials; some providers require app-specific passwords |
| Google OAuth errors | Confirm the service account has domain-wide delegation and the https://mail.google.com/ scope is authorized |
| Timeouts on large mailboxes | Consider adding --maxbytespersecond to throttle, or splitting into multiple runs. Increasing MAX_WORKERS may also effectively increase total throughput but watch out for rate limits. |