Migrating Mail Between Servers with imapsync

When you change hosting or mail provider, messages have to move together with folders, read flags and dates. The imapsync utility copies mail from one IMAP server to another directly, mailbox by mailbox. It can be run repeatedly: messages already transferred are skipped, so the final pass before the switchover takes minutes.
What you need
- the IMAP server addresses — old and new;
- mailbox logins and passwords on both sides;
- mailboxes already created on the new server: imapsync transfers contents, it does not create accounts;
- a computer or a VPS with Docker to run the transfer.
If the account uses two-factor authentication, create an app password in the mail service settings and use it instead of the main one.
Installation
The easiest way is to run imapsync in a container — you avoid installing dozens of Perl modules:
docker pull gilleslamiral/imapsync
Check it:
docker run --rm gilleslamiral/imapsync imapsync --version
The Docker installation guide covers setting up Docker. Without Docker, the imapsync project site has installation steps for each distribution.
Step 1. Test the connection
First make sure the logins and passwords work. --justlogin only tests authentication and copies nothing:
docker run --rm gilleslamiral/imapsync imapsync \
--host1 imap.old-server.com --user1 user@example.com --password1 'old_password' \
--host2 mail.new-server.com --user2 user@example.com --password2 'new_password' \
--justlogin
Parameters ending in 1 refer to the source server, those ending in 2 to the destination. Put passwords in single quotes so the shell does not interpret special characters.
Step 2. Dry run
--dry shows what would be done without changing anything:
docker run --rm gilleslamiral/imapsync imapsync \
--host1 imap.old-server.com --user1 user@example.com --password1 'old_password' \
--host2 mail.new-server.com --user2 user@example.com --password2 'new_password' \
--automap --dry
Check the folder list in the output: which folders were found on the old server and what they become on the new one. --automap matches special folders that are named differently on different servers, such as “Sent Items” and Sent, or “Deleted” and Trash.
Step 3. Transfer
Remove --dry and run the transfer:
docker run --rm gilleslamiral/imapsync imapsync \
--host1 imap.old-server.com --user1 user@example.com --password1 'old_password' \
--host2 mail.new-server.com --user2 user@example.com --password2 'new_password' \
--automap
At the end imapsync prints a summary: how many messages were transferred, how many skipped, and whether there were errors. If there are errors, run the command again — only what is missing gets copied.
Useful options
| Option | What it does |
|---|---|
--dry |
dry run, no changes |
--justlogin |
test authentication only |
--justfolders |
create the folder structure without messages |
--automap |
match special folders automatically |
--exclude 'Spam|Junk|Trash' |
skip the listed folders |
--folder INBOX |
transfer a single folder |
--maxage 365 |
only messages newer than the given number of days |
--maxsize 26214400 |
skip messages larger than the given size, in bytes |
--f1f2 'Old=New' |
rename a folder during transfer |
--port1 993 --ssl1 |
port and encryption for the source server |
--passfile1 file |
read the password from a file instead of the command line |
--delete2 |
delete messages on the new server that do not exist on the old one |
Notes on popular services
- Gmail. An app password is required. Add
--gmail1(or--gmail2if Gmail is the destination): it enables suitable settings for labels and the service’s limits. Mind Gmail’s daily transfer quotas — a large mailbox may take several days. - Microsoft 365 and Outlook.com. Use
--office1or--office2. Plain password login may be disabled by the administrator. - Self-signed certificate. If the old server uses an untrusted certificate, imapsync accepts it by default, but make sure you are connecting to the right address.
Bulk migration
For several mailboxes, prepare a users.txt file — one line per mailbox, fields separated by semicolons:
user1@example.com;old_password;user1@example.com;new_password
user2@example.com;old_password;user2@example.com;new_password
The migrate.sh script:
#!/bin/bash
mkdir -p logs
while IFS=';' read -r u1 p1 u2 p2; do
[ -z "$u1" ] && continue
echo "=== $u1 -> $u2"
docker run --rm gilleslamiral/imapsync imapsync \
--host1 imap.old-server.com --user1 "$u1" --password1 "$p1" \
--host2 mail.new-server.com --user2 "$u2" --password2 "$p2" \
--automap --nolog < /dev/null > "logs/$u1.log" 2>&1
tail -n 3 "logs/$u1.log"
done < users.txt
chmod +x migrate.sh
./migrate.sh
Each mailbox’s log is saved in the logs directory. Restrict access to the password file (chmod 600 users.txt) and delete it after the migration.
Switchover order without losing mail
- Create the mailboxes on the new server.
- Lower the TTL of the domain’s MX record to 300 seconds in advance — the switch goes faster.
- Do the first pass with imapsync. It is the longest one; users keep working on the old server.
- Switch the MX record to the new server.
- Wait for DNS to propagate — some mail still arrives at the old server during that time.
- Do the final pass. It copies the messages that arrived during the switch.
- Reconfigure users’ mail clients for the new server.
- Keep the old server running for a few more days and repeat the pass before shutting it down.
If the new server is your own, check the SPF, DKIM and DMARC records after the migration: the procedure is covered in the guides for HestiaCP and Mailcow. In Mailcow the transfer can be configured right in the panel: its sync jobs use the same imapsync.
Common problems
Authentication failed. Wrong password, IMAP access is disabled, or an app password is required.- Messages are duplicated on a repeat run. The server alters message headers. Add
--useheader 'Message-Id'so messages are compared by identifier only. - Folders with non-Latin names look wrong. Run with
--dry --justfoldersfirst and, if needed, set the mapping with--f1f2. - The transfer is interrupted. Just run the command again: imapsync continues where it stopped.
- Not enough space. Check the mailbox quota on the new server before the transfer.


