Files
hermes-skills/skills/devops/debt-recovery-workflow/references/imap-migration-pattern.md
T

2.6 KiB

IMAP Email Migration Pattern

Source-to-destination IMAP migration using Python stdlib (imaplib). Used for migrating email accounts from SiteGround to MXroute.

Known Hosts

Provider IMAP Host Port
SiteGround c1113726.sgvps.net 993
MXroute heracles.mxrouting.net 993
germainebrown.com mail.germainebrown.com 993
iCloud imap.mail.me.com 993

Pattern

import imaplib, ssl
ctx = ssl.create_default_context()

# Connect old
old = imaplib.IMAP4_SSL(OLD_HOST, 993, ssl_context=ctx, timeout=15)
old.login(email, old_pw)

# Connect new
new = imaplib.IMAP4_SSL(NEW_HOST, 993, ssl_context=ctx, timeout=15)
new.login(email, new_pw)

# Get folder list
for line in old.list()[1]:
    decoded = line.decode()
    # IMAP list format: (flags) "." "foldername"
    # Extract the last quoted segment
    parts = decoded.split('"')
    folder = parts[-2] if len(parts) >= 2 else decoded.split()[-1]

# Copy messages
for uid in uids:
    r = old.fetch(uid, "(RFC822)")
    if r[0] == "OK" and isinstance(r[1][0], tuple):
        new.append(target_folder, None, None, r[1][0][1])

Pitfalls

  • SiteGround folder list is nonstandard — subfolders show as INBOX.Trash, INBOX.Sent, etc. but the LIST response uses "." as separator. Parse carefully — there are many redundant . entries. Only folders with actual content (INBOX.Trash, INBOX.Sent, etc.) are real.
  • Timeout on large folders — 60s is not enough for 100+ messages. Set terminal timeout to 300 for full migration.
  • Duplicate on retry — if a migration is interrupted and restarted, messages get appended twice. No built-in dedup during copy. Mapped folders (Trash, Sent) may show 2x expected count after retry. Clean up via MXroute webmail.
  • Folder name mapping — SiteGround uses dotted hierarchy (INBOX.Trash), MXroute uses flat names (Trash). Map explicitly per account.
  • MXroute folder creationnew.create("Trash") works for flat names but can fail if the folder already exists (catch and pass).
  • MXroute LIST response may show 6 . entries with no content — these are cursor entries, not actual folders. Filter them out with if fname == ".": continue.
  • SiteGround LIST % pattern may errorlist('', 'INBOX.*') returns BAD on SiteGround. Use list() with no pattern and parse the full response.
  • List response parsing is provider-specific — the HMXroute format is (flags) "." Trash (simple), while SiteGround is (flags) "." "INBOX.Trash" (quoted). Use rsplit('"', 2) for max compatibility across providers.