Files
hermes-skills/skills/devops/python-web-service-deployment/references/imap-migration-pattern.md
T

55 lines
2.1 KiB
Markdown

# IMAP-to-IMAP Email Migration
Migrate all emails from one provider to another for a domain. Used for moving boy's emails (greyson@, garrison@) from SiteGround to MXroute.
## Process
1. **DNS check** — Verify MX records point to the destination provider:
```bash
dig +short MX iamgmb.com
```
2. **Verify old account access**:
```bash
python3 -c "
import imaplib, ssl
ctx = ssl.create_default_context()
s = imaplib.IMAP4_SSL('old_host', 993, ssl_context=ctx, timeout=10)
s.login('email@domain.com', 'password')
r = s.select('INBOX')
print(f'{r[1][0].decode()} messages in INBOX')
s.logout()
"
```
3. **List all folders** — SiteGround uses `INBOX.` prefix for subfolders; MXroute uses flat top-level folder names.
4. **Migrate each folder**:
- Map old folder names to new folder names (e.g. `INBOX.Deleted Messages` → `Trash`)
- Create destination folders on new server
- Copy messages preserving dates via IMAP APPEND
5. **Verify** — Count messages on new server match old server per folder.
## Folder Mapping (SiteGround → MXroute)
| SiteGround | MXroute |
|-----------|---------|
| INBOX | INBOX |
| INBOX.Trash | Trash |
| INBOX.Deleted Messages | Trash |
| INBOX.Sent | Sent |
| INBOX.Sent Messages | Sent |
| INBOX.Drafts | Drafts |
| INBOX.spam | INBOX.spam |
| INBOX.Junk | Junk |
| INBOX.Archive | Archive |
## Pitfalls
- **Folder listing format differs** — SiteGround uses `INBOX.` subfolder notation and returns `"."` entries from LIST (ignore those). MXroute returns flat format `(flags) "." folder_name`.
- **IMAP responses are bytes** — Decode with `decode()`, not `.decode('ascii')`. UTF-8 is safe.
- **Rate limits** — If migrating many messages (300+ per folder), batch in groups of 50 and add `time.sleep(0.5)` between batches.
- **Deduplication** — Messages ARE appended. If the script runs twice, duplicates happen. Track by `(folder, UID)` composite key.
- **Password visibility** — SMTP/IMAP passwords are passed on the command line in heredocs. Use `ps aux | grep` awareness. For production, read from a file.