Docs / Email Servers / Migrating Email Between Servers with imapsync

Migrating Email Between Servers with imapsync

By Admin · Mar 15, 2026 · Updated Apr 23, 2026 · 430 views · 4 min read

imapsync is a powerful command-line tool for migrating email between IMAP servers. It synchronizes mailboxes including all folders, flags, and message metadata while handling differences between server implementations. This guide covers migration planning, execution, and validation for both single-user and bulk migrations.

Installation

# Ubuntu/Debian
sudo apt install imapsync

# From source (latest version)
sudo apt install libauthen-ntlm-perl libcgi-pm-perl libcrypt-openssl-rsa-perl \
    libdata-uniqid-perl libencode-imaputf7-perl libfile-copy-recursive-perl \
    libfile-tail-perl libio-compress-perl libio-socket-inet6-perl \
    libio-socket-ssl-perl libio-tee-perl libhtml-parser-perl libjson-webtoken-perl \
    libmail-imapclient-perl libparse-recdescent-perl libmodule-scandeps-perl \
    libreadonly-perl libregexp-common-perl libsys-meminfo-perl libterm-readkey-perl \
    libtest-mockobject-perl libtest-pod-perl libunicode-string-perl liburi-perl \
    libwww-perl libtest-nowarnings-perl libtest-deep-perl libtest-warn-perl \
    make cpanminus

wget https://imapsync.lamiral.info/dist2/imapsync
chmod +x imapsync
sudo mv imapsync /usr/local/bin/

Basic Migration

# Migrate a single mailbox
imapsync \
    --host1 old-server.example.com --user1 user@example.com --password1 'OldPass' \
    --host2 new-server.example.com --user2 user@example.com --password2 'NewPass' \
    --ssl1 --ssl2

Common Options

# Dry run (test without actually copying)
imapsync \
    --host1 old.example.com --user1 user@example.com --password1 'pass' \
    --host2 new.example.com --user2 user@example.com --password2 'pass' \
    --ssl1 --ssl2 --dry --justlogin

# Exclude folders
imapsync ... --exclude "Trash|Spam|Junk|Drafts"

# Include only specific folders
imapsync ... --include "INBOX|Sent|Archives"

# Rename folders during migration
imapsync ... --regextrans2 "s/Sent Items/Sent/" --regextrans2 "s/Deleted Items/Trash/"

# Map folder separator (Exchange \ to Dovecot /)
imapsync ... --sep1 "/" --sep2 "/"

# Limit bandwidth
imapsync ... --maxbytespersecond 100000    # 100KB/s

# Skip messages larger than 50MB
imapsync ... --maxsize 52428800

Bulk Migration Script

#!/bin/bash
# /usr/local/bin/bulk-migrate.sh
# Migrate multiple users from CSV file

CSV_FILE="/root/migration-users.csv"
LOG_DIR="/var/log/imapsync"
OLD_HOST="old-mail.example.com"
NEW_HOST="new-mail.example.com"

mkdir -p "$LOG_DIR"

# CSV format: email,old_password,new_password
while IFS=',' read -r email old_pass new_pass; do
    echo "[$(date)] Migrating $email..."

    imapsync \
        --host1 "$OLD_HOST" --user1 "$email" --password1 "$old_pass" --ssl1 \
        --host2 "$NEW_HOST" --user2 "$email" --password2 "$new_pass" --ssl2 \
        --exclude "Trash|Junk" \
        --addheader \
        --useheader "Message-ID" --useheader "Date" \
        --logfile "$LOG_DIR/$email.log" \
        --errorsmax 50 \
        2>&1

    if [ $? -eq 0 ]; then
        echo "[$(date)] SUCCESS: $email"
    else
        echo "[$(date)] FAILED: $email — check $LOG_DIR/$email.log"
    fi

done < "$CSV_FILE"

Migration from Specific Providers

Gmail to Self-Hosted

# Gmail requires App Password (enable 2FA first, then create App Password)
imapsync \
    --host1 imap.gmail.com --user1 user@gmail.com --password1 'app-password' --ssl1 \
    --host2 new-server.example.com --user2 user@example.com --password2 'NewPass' --ssl2 \
    --exclude "\[Gmail\]/All Mail" --exclude "\[Gmail\]/Important" \
    --regextrans2 "s/\[Gmail\]\/Sent Mail/Sent/" \
    --regextrans2 "s/\[Gmail\]\/Starred/Flagged/" \
    --regextrans2 "s/\[Gmail\]\/Drafts/Drafts/"

Office 365 to Self-Hosted

imapsync \
    --host1 outlook.office365.com --user1 user@company.com --password1 'Pass' --ssl1 \
    --host2 new-server.example.com --user2 user@company.com --password2 'NewPass' --ssl2 \
    --office1 \
    --regextrans2 "s/Sent Items/Sent/" \
    --regextrans2 "s/Deleted Items/Trash/"

Incremental Sync

# imapsync is idempotent — run it multiple times for incremental updates
# First run: full migration
# Subsequent runs: only sync new/changed messages

# Strategy for minimal downtime:
# 1. Initial sync (days before cutover)
imapsync --host1 old --user1 user --password1 pass --host2 new --user2 user --password2 pass --ssl1 --ssl2

# 2. Update DNS (MX records to new server)
# 3. Final sync (catch messages received between initial sync and DNS switch)
imapsync --host1 old --user1 user --password1 pass --host2 new --user2 user --password2 pass --ssl1 --ssl2

# imapsync uses Message-ID to identify duplicates and skips already-synced messages

Validation

# Compare mailbox sizes
imapsync ... --justfolders --justfoldersizes

# Check logs for errors
grep -c "error" /var/log/imapsync/user@example.com.log
grep "could not" /var/log/imapsync/user@example.com.log

# Compare message counts per folder
imapsync ... --dry --justfoldersizes 2>&1 | grep -E "^Folder|messages"

Performance Tuning

# Use multiple connections for faster migration
imapsync ... --threads 4

# Disable unnecessary checks
imapsync ... --nofoldersizes --fast

# Use UID-based sync (faster than Message-ID)
imapsync ... --useuid

Best Practices

  • Always do a dry run (--dry --justlogin) first to verify credentials and connectivity
  • Run initial migration days before cutover, then do a final sync after DNS changes
  • Use --logfile for every migration for troubleshooting and audit trails
  • Exclude Trash and Junk folders to save time and storage
  • Test folder mapping with --justfolders --dry before migrating messages
  • For large mailboxes (10GB+), run migrations overnight to minimize bandwidth impact
  • Verify message counts and folder structure after migration

Was this article helpful?