- Python 70%
- Shell 30%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .gitignore | ||
| currentpwd-to-proton.sh | ||
| LICENSE | ||
| README.md | ||
| sanitise_mbox.py | ||
imap-sanitiser
Migration tool for pushing legacy mbox archives into Proton Mail via the Proton Mail Bridge IMAP interface.
Proton Bridge enforces strict RFC 5322 compliance. Real-world email archives spanning decades do not. This tool sanitises mbox files to bridge's standards before upload, handling malformed address headers, legacy character encodings, and missing envelope lines.
What It Does
- Rebuilds address headers (From, To, Cc, Bcc, Reply-To, Return-Path, Sender) to ensure every address is wrapped in angle brackets. Bare names like
MAILER-DAEMONora.friendget a fallback<unknown@localhost>. - Strips the Sender header entirely, which causes parse failures in Bridge.
- Converts legacy character encodings (windows-1252, cp1252, iso-8859-1, latin-1, and others) to UTF-8.
- Preserves mbox envelope lines by parsing raw bytes line-by-line instead of using Python's
email.message_from_bytes(), which silently strips them. - Injects a Date header if one is missing.
- Concatenates all mbox files in a
.sbddirectory tree into a single temp file for batch upload. - Diverts failures to a separate
failed_<folder>.mboxfor manual review.
The Trade-Off
Display names are stripped from address headers. A message that originally showed From: "Alex" <alex@example.com> will show From: <alex@example.com> after sanitisation. The email address, subject, body, and attachments are all preserved. The display name is lost. Given the alternative (zero messages imported), that is an acceptable trade.
Prerequisites
- Proton Mail Bridge installed and running (local IMAP at
127.0.0.1:1143) - Python 3 (standard library only, no pip packages required)
- imap-upload (
imap_upload.py) installed and on yourPATHor referenced by full path in the script - Your Bridge IMAP credentials, sourced from Bridge's internal info tool
Setup
1. Get your Bridge credentials
Proton Bridge does not use your email address as the IMAP username. Retrieve the generated credentials from Bridge:
protonmail-bridge --cli
Inside the CLI, use the info command to display your IMAP username and password.
2. Store credentials securely
Create ~/.proton_bridge_creds:
cat > ~/.proton_bridge_creds << 'EOF'
export IMAP_USER="your_bridge_username"
export IMAP_PASS="your_bridge_password"
EOF
chmod 600 ~/.proton_bridge_creds
Source it before running the migration: source ~/.proton_bridge_creds
3. Configure the script
Edit currentpwd-to-proton.sh and update:
- TMP_DIR — temporary working directory for concatenated mbox files
- IMAP_HOST / IMAP_PORT — if your Bridge instance runs elsewhere
- The path to imap_upload.py if it is not on your PATH
Usage
./currentpwd-to-proton.sh <path-to-.sbd-directory> <IMAP-target-folder>
Examples
Migrate a Yahoo archive
./currentpwd-to-proton.sh "Yahoo!.sbd" Folders/alt/heim/yahoo
The script will:
Create the target IMAP folder hierarchy if it does not exist
Concatenate all mbox files in the .sbd directory into one temp file
Count and report messages per folder
Run the Python sanitiser on the combined mbox
Upload the sanitised file via imap-upload
Report total, successful, and failed message counts
Save failed messages to failed_<folder>.mbox for manual review
Clean up temporary files
Known Issues
- Folders created via IMAP do not auto-subscribe. After migration, subscribe to each folder in Proton's web UI or add m.subscribe() to the inline Python in the script.
- imaplib has a hardcoded 1 MB line-length limit. For folders with hundreds of thousands of messages, override imaplib._MAXLINE before running SEARCH commands.
- OK: 0 from imap-upload is a silent failure. If imap-upload cannot parse the mbox file, it reports zero messages uploaded successfully, not an error. Always check the OK count, not just the error count.
Misc
Background
Full narrative of the migration, including all seven failure modes encountered and the lessons learned, is documented in the blog post: Migrating 30,000+ Personal Emails to Proton Mail: A Field Report
LICENSE
MIT. See LICENSE
Contributing
This was built for a specific migration. If you hit a case it does not handle, fork it and adapt. Pull requests welcome if they fix genuine bugs rather than edge cases specific to one archive.