Install
The CLI is free, with no size limit. It needs Node.js 22 or newer on macOS, Linux or Windows. Check with node --version.
$ npm install -g vayamail $ vayamail --version
Or run it without installing anything permanent:
$ npx vayamail@latest migrate --from office@example.com --to office@example.comUpdate later with npm install -g vayamail@latest. Every command explains itself with --help, e.g. vayamail migrate --help.
Prefer to have an AI assistant walk you through it?
Give ChatGPT, Claude or your coding agent this prompt. It asks you the right questions, installs the tool, and never asks for your passwords in the chat.
Quick start: move one mailbox
The usual case: same address, new host. Create the mailbox on the new host first, with its password.
1. See what would happen
The servers are found from the address. You are asked for both passwords (typing is hidden), then shown the folder plan and how much would be copied. Nothing is written.
$ vayamail migrate --from office@example.com --to office@example.com --dry-run2. Copy
The same command without
--dry-run. It asks once more before it starts. The old mailbox is only read: nothing there is changed, moved or marked as read.$ vayamail migrate --from office@example.com --to office@example.com --report report.csv ... Done in 14m 22s. 6,403 copied, 12 already there. state saved to ~/.vayamail/state/3f9a1c.json · sync new mail later: vayamail sync 3f9a1c
Note the job id at the end (
3f9a1chere). If the copy is interrupted (laptop asleep, network gone, Ctrl+C), runvayamail resume 3f9a1cand it continues where it stopped.3. Switch the domain, then catch the stragglers
Point the domain’s MX records at the new host. Mail that reached the old mailbox in the meantime is picked up by a sync, which only looks at new messages:
$ vayamail sync 3f9a1cRun it again a day later if you like. Messages already copied are always skipped, so nothing is ever duplicated.
Different addresses work the same way: --from old@example.com --to new@example.net. If a server isn’t found, give it with --from-host / --to-host. The provider guides list the server names for cPanel, Plesk, Hostinger, Gmail, Outlook and others.
Passwords
Passwords are only used to log in to the two mail servers, straight from your computer. They are never sent to VayaMail and never written to disk. There are three ways to give them, tried in this order:
- VAYAMAIL_FROM_PASS / VAYAMAIL_TO_PASS
- Environment variables, handy in scripts and CI.
- --from-pass-file / --to-pass-file
- A file holding only the password (one line). Keep it private:
chmod 600 old.txt. - (nothing)
- A hidden prompt asks for it.
There is deliberately no --password flag: passwords typed as flags end up in your shell history.
Gmail and Outlook.com need an app password instead of your normal one; see the Gmail and Outlook guides. Microsoft 365 work accounts that only allow Microsoft sign-in aren’t supported yet.
Commands
vayamail migrate
Copy every folder from the old mailbox to the new one. Sent, Drafts, Trash and Spam are matched by their role whatever they are called; other folders are created on the new side with the same names. Dates, read/unread, flags and attachments are kept.
$ vayamail migrate --from office@example.com --to office@example.com $ vayamail migrate --from office@example.com --from-host server123.example-host.com --insecure \ --to office@example.com --to-host imap.example.net --since 2024-01-01 --exclude "Archive/*"
Server options
- --from <address>
- Old mailbox address. Its IMAP server is found automatically.
- --from-host <host>
- IMAP server of the old mailbox, when autodetect picks the wrong one or finds none.
- --from-port <port>
- Port. Default 993 with
tls, 143 withstarttlsornone. - --from-security <mode>
tls(port 993),starttls(143) ornone(unencrypted, only for servers on your own network).- --from-user <user>
- Login name, if it is not the email address (some hosts use only the part before the @).
- --from-pass-file <file>
- Read the password from a file instead of asking for it.
- --to … --to-pass-file
- The same six options for the new mailbox.
Copy options
- --dry-run
- Connect, plan and count. Writes nothing.
- --include-trash
- Also copy Trash. Left out by default.
- --include-junk
- Also copy Spam / Junk. Left out by default.
- --since <YYYY-MM-DD>
- Only messages received on or after this date.
- --exclude <pattern>
- Skip folders that match, e.g.
"Archive/*". Repeat it for more patterns. - --map <Source=Destination>
- Send one folder somewhere else, e.g.
"INBOX.Sent Messages=Sent". Repeatable. - --connections <1–6>
- Connections per mailbox on each side. Default 2, which shared hosting tolerates well.
- --insecure
- Accept a certificate issued for a different name. Common on shared hosting; see Troubleshooting.
- --report <file>
- Write the report to
report.csvorreport.json: every folder, plus every message that was not copied and why. - --json
- Newline-delimited JSON progress events on stdout, for scripts.
- -y, --yes
- Start without asking for confirmation.
- --config <file>
- Read servers and options from a YAML file (see Config file). Flags override the file.
- --incremental
- Only look at messages newer than the ones this job already copied. You rarely need it:
vayamail sync <jobId>does exactly this for a saved job.
vayamail folders
Print the folder plan only: which folder goes where, and which are skipped. Takes the same server options as migrate, plus --include-trash, --include-junk, --exclude, --map and --json. Use it to get --map right before a big run.
$ vayamail folders --from office@example.com --to office@example.comvayamail test
Log in to one server and list its folders with message counts and size. Good for checking a password or a server name.
$ vayamail test --host mail.example.com --user office@example.com- --host, --user
- Server and login name.
- --port, --security
- Default 993 and
tls. - --pass-file <file>
- Read the password from a file.
- --insecure, --json
- As for migrate.
vayamail detect
Show which IMAP server an address uses and how it was found (known provider, Thunderbird’s database, DNS, MX records, common names). No password needed.
$ vayamail detect office@example.comvayamail resume <jobId> · vayamail sync <jobId>
resume continues a job that stopped; sync copies only mail that arrived since the last run. Both reuse the saved servers and options, ask for the passwords again, and accept --from-pass-file, --to-pass-file, --report and --json. See Resume and sync.
vayamail bulk <file.csv>
Migrate many mailboxes from a CSV, a few at a time. See below.
vayamail import <files or folders…> --to <address>
Upload mail saved on your computer into a mailbox. See Importing saved mail.
Many mailboxes from a CSV
One line per mailbox. The header row is optional; the two host columns can be left empty to autodetect, or hold mail.example.com, mail.example.com:143 or imaps://mail.example.com:993. Quote a password that contains a comma. Lines starting with # are ignored.
Start from the CSV template: four example lines with notes, ready to fill in a spreadsheet.
# accounts.csv src_email,src_password,dst_email,dst_password,src_host,dst_host office@example.com,old-password,office@example.com,new-password,, ana@example.com,"pass,with,commas",ana@example.com,new-password-2,mail.example.com,imap.example.net
$ vayamail bulk accounts.csv --concurrency 3 --report bulk-report.csv- --concurrency <n>
- Mailboxes migrated at the same time. Default 3; keep it low when they all live on the same shared server.
- --connections <1–6>
- Connections per mailbox on each side. Default 2.
- --include-trash, --include-junk, --since
- As for migrate, applied to every mailbox.
- --insecure
- Accept certificates issued for a different name, for every server.
- --report <file>
- One combined report for all mailboxes (.csv or .json).
- --json
- JSON events, each tagged with its mailbox.
Each mailbox gets its own job id, printed next to it, for resume and sync. The CSV holds passwords in plain text: keep it private (chmod 600 accounts.csv) and delete it when you are done.
Importing saved mail
For mail that is no longer on a server: point import at the files or folders a mail app saved, and it uploads them into a mailbox, folder by folder. Run the same command again and it continues where it stopped, skipping what is already there.
$ vayamail import ~/Downloads/Takeout/Mail/All\ mail\ Including\ Spam\ and\ Trash.mbox --to office@example.com $ vayamail import Archive.pst --to office@example.com --dry-run $ vayamail import ~/Library/Thunderbird/Profiles/abc.default/Mail/Local\ Folders --to office@example.com
- Thunderbird
- The profile’s
Mail/Local Foldersfolder, or the whole profile folder. - Apple Mail
- The
Name.mboxfolders made by Mailbox › Export Mailbox. - Gmail
- The
.mboxfile from Google Takeout. Each message goes to one folder, chosen from its labels. - Outlook
- A
.pstfile (File › Open & Export › Import/Export › Export to a file) or an.ost. - Any client
- A folder of
.emlfiles; it becomes a folder with the same name.
Read, replied, starred and Thunderbird tags are kept when the files record them; otherwise messages arrive as read. import takes the --to server options and the copy options of migrate. Step-by-step exports are in the guides for Thunderbird, Apple Mail, Gmail Takeout and Outlook .pst.
Config file
Instead of long command lines, keep the settings in a YAML file and run vayamail migrate --config job.yaml. Flags on the command line win over the file. Passwords don’t belong in it: use the prompt, the environment variables, or passFile.
# job.yaml from: email: office@example.com host: server123.example-host.com # optional, autodetected otherwise insecure: true # certificate issued for the hosting company to: email: office@example.com host: imap.example.net passFile: ./new-password.txt # optional; also: port, user, security options: since: 2024-01-01 exclude: ["Archive/*"] map: INBOX.Sent Messages: Sent includeTrash: false includeJunk: false connections: 2
Resume and sync
Every run gets a short job id. The CLI remembers the job in your home folder, never the passwords:
- ~/.vayamail/jobs/<id>.json
- Servers, options and the folder plan, so
resumeandsyncneed nothing but the passwords. - ~/.vayamail/state/<id>.json
- Progress per folder: what was copied, so nothing is copied twice.
- VAYAMAIL_HOME
- Set it to keep these files somewhere else.
Even without the state, a rerun never duplicates mail: before copying a folder, VayaMail checks what the new mailbox already holds (by Message-ID and size) and skips it. That is why running migrate twice is safe.
Reports and exit codes
The summary at the end says how many messages were copied, already there, or not copied. --report file.csv (or .json) lists every folder and every message that was not copied with the reason, for example a message larger than the new host accepts.
- exit 0
- Everything was copied (or was already there).
- exit 1
- Done, but some messages were not copied. They are listed in the report.
- exit 2
- Stopped: wrong password, server not reachable, bad options.
With --json, progress comes as one JSON object per line (job:start, plan:ready, folder:start, progress, folder:done, job:done…), ready for jq or your own scripts.
$ vayamail migrate --config job.yaml --yes --json | jq -c 'select(.type == "folder:done")'Troubleshooting
- “certificate not valid for mail.example.com”
- Common on shared hosting: the certificate belongs to the hosting company’s server (e.g.
server123.example-host.com). When the CLI can read that name it connects with it automatically and says so. Otherwise use that server name with--from-host, or accept the mismatch with--insecure. - “no IMAP server found”
- Give the server yourself with
--from-host/--to-host. Your host’s help pages or the mail settings in webmail show it;vayamail testconfirms it works. - Authentication failed
- Check the password with
vayamail test. Some hosts want only the part before the @ as the login (--from-user office). Gmail and Outlook.com need an app password. - “Too many connections” or slow progress
- The server is limiting you. VayaMail waits and retries on its own; lower the pressure with
--connections 1(and--concurrency 1in bulk). - Some messages were not copied
- The report says why. Usually the message is bigger than the new host accepts, or the new mailbox is full. Everything else carries on.
- Something else
- Run it again with
VAYAMAIL_DEBUG=1for the full error, and write to hello@vayamail.com with the output (remove anything private).
Rather not use a terminal? The web app does the same in three steps.
Start in the browser