Move Mail Safely with movemail.mailutils

movemail.mailutils moves messages out of a mailbox and, by default, deletes the source copies the moment the transfer succeeds. That is worth knowing before your first run touches a real inbox. The examples use GNU Mailutils 3.17, packaged here as mailutils 1:3.17-1.1build3. Allow about fifteen minutes to work through a safe test and a real move.

You need a shell, a readable source mailbox and a destination path you can write. Remote mail also needs the server, account details and a protocol. No example here needs elevated privileges when both paths belong to your user: use sudo only when mailbox permissions genuinely require it, and never put a password where shell history or a process list can see it.

1. Confirm which movemail you are running

This check is read-only:

$ command -v movemail.mailutils
/usr/bin/movemail.mailutils
$ movemail.mailutils --version
movemail.mailutils (GNU Mailutils) 3.17

The plain movemail name might also exist as an alias or a different executable. Use the full movemail.mailutils name in scripts when it matters which implementation runs. Its required arguments are an inbox-url followed by a destination file, with an optional POP password as a third.

2. Pick the source URL format

Do not paste a real password into a URL typed into a terminal. If a username contains @, URL-encode it as %40 so it is not mistaken for the host separator.

Checkpoint: inspect the path before moving anything.

$ SOURCE='/path/to/inbox'
$ DEST='/path/to/moved-mail'
$ test -r "$SOURCE" && echo 'source is readable'
source is readable
$ test ! -e "$DEST" && echo 'destination does not exist'
destination does not exist

Swap in real paths. That last test is a safety check, not a rule: pick a new destination if the existing file already holds mail you need.

3. Run a non-destructive test transfer

Use --preserve while you are still learning the command; it keeps the source instead of deleting transferred messages. Add --max-messages to cap the trial to one:

$ movemail.mailutils --no-config --preserve --max-messages=1 \
    "file://$SOURCE" "$DEST"
$ printf 'exit status: %s\n' "$?"
exit status: 0
$ test -s "$DEST" && echo 'destination is non-empty'
destination is non-empty

--no-config skips site and user Mailutils configuration, which is useful for a controlled test. Leave it out if your normal setup deliberately supplies configuration the mailbox needs. The destination is a mailbox file, not a report: do not expect a summary of subjects on standard output.

Check both sides afterwards:

$ wc -c "$SOURCE" "$DEST"
  1234 /path/to/inbox
   456 /path/to/moved-mail
  1690 total
$ sed -n '1,12p' "$DEST"
From [email protected] ...
Subject: example subject

Your byte counts and headers will differ. What matters is a zero exit status, a non-empty destination, and a source that still has its original messages. Keep the source until your mail software has opened and validated the destination.

4. Know the destructive default

Warning: without --preserve, movemail removes messages from the source once they transfer. This is a move, not a copy. Do not run it against a production inbox until the preserved test has worked and you have a recovery plan.

Back up first, for a local file you own:

$ cp --preserve=all "$SOURCE" "$SOURCE.backup"
$ movemail.mailutils --no-config "file://$SOURCE" "$DEST"
$ test -s "$DEST" && echo 'move produced a destination'
move produced a destination

Do not delete $SOURCE.backup until the destination opens and contains what you expect. There is no generic undo: recovery means restoring the backup, or falling back on the mail system's own copy, snapshot or server-side retention.

5. Control ordering and repeat retrieval

6. Diagnose failures without guessing

Start with the exit status and the exact source URL: a misspelled local path, an unreadable spool file, a wrong protocol and a failed remote login are four different problems. Check local access without touching the mailbox:

$ ls -l "$SOURCE"
$ test -r "$SOURCE" && echo readable
readable
$ test -w "$(dirname "$DEST")" && echo 'destination directory is writable'
destination directory is writable

If a remote login fails, do not paste credentials into a command that ends up in a shared ticket or a shell history. Use the password prompt or Mailutils' own configuration mechanism, pick pops or imaps when encryption is required, and confirm the server's actual protocol and port.

Tip: --verbose adds diagnostics and --progress-meter shows progress on a long transfer, but neither one repairs permissions, authentication or mailbox corruption. If a transfer stops halfway, keep both source and destination, record the command, and inspect the destination before retrying: a blind retry can duplicate messages.

Done means