Restore¶
Restore uploads emails from your local SQLite database back to an IMAP server. It preserves the original mailbox structure, flags (read/unread), and dates.
Why Restore?¶
- Migration — move emails between servers (Hostinger to Gmail, Gmail to Outlook, etc.)
- Disaster recovery — re-upload emails after a server failure
- Account merge — consolidate multiple accounts into one
- Testing — populate a test server with real data
Restore All Mailboxes¶
Each email is uploaded to its original mailbox. If a mailbox doesn't exist on the target server, it's created automatically.
# Code above omitted 👆
# Force re-download (skip duplicate check)
result = app.sync(skip_duplicates=False)
# Code below omitted 👇
👀 Full file preview
"""Sync and restore emails."""
from email_profile import Email
def main() -> None:
with Email.from_env() as app:
# Sync all mailboxes (compares by Message-ID)
result = app.sync()
print(f"Synced: {result.inserted} new, {result.skipped} skipped")
# Sync one mailbox
result = app.sync(mailbox="INBOX")
print(f"INBOX: {result.inserted} new")
# Force re-download (skip duplicate check)
result = app.sync(skip_duplicates=False)
# Restore all mailboxes to server (compares by Message-ID)
count = app.restore()
print(f"Restored {count} emails")
# Restore one mailbox
count = app.restore(mailbox="INBOX")
print(f"Restored {count} to INBOX")
# Force re-upload (skip duplicate check)
count = app.restore(skip_duplicates=False)
# Control parallelism
result = app.sync(max_workers=5)
count = app.restore(max_workers=5)
if __name__ == "__main__":
main()
Restore One Mailbox¶
# Code above omitted 👆
count = app.restore()
print(f"Restored {count} emails")
# Code below omitted 👇
👀 Full file preview
"""Sync and restore emails."""
from email_profile import Email
def main() -> None:
with Email.from_env() as app:
# Sync all mailboxes (compares by Message-ID)
result = app.sync()
print(f"Synced: {result.inserted} new, {result.skipped} skipped")
# Sync one mailbox
result = app.sync(mailbox="INBOX")
print(f"INBOX: {result.inserted} new")
# Force re-download (skip duplicate check)
result = app.sync(skip_duplicates=False)
# Restore all mailboxes to server (compares by Message-ID)
count = app.restore()
print(f"Restored {count} emails")
# Restore one mailbox
count = app.restore(mailbox="INBOX")
print(f"Restored {count} to INBOX")
# Force re-upload (skip duplicate check)
count = app.restore(skip_duplicates=False)
# Control parallelism
result = app.sync(max_workers=5)
count = app.restore(max_workers=5)
if __name__ == "__main__":
main()
Skip Duplicates¶
By default, restore checks if an email already exists on the server (by Message-ID) and skips it. Disable this for faster restores when you know the server is empty:
count = app.restore(skip_duplicates=False)
Parallel Workers¶
Like sync, restore uses threads — one per mailbox:
count = app.restore(max_workers=5)
Output¶
Each mailbox shows a progress bar while uploading:
- uploaded — emails sent to the server
- skipped — emails already on the server (duplicate detection)
Restore to a Different Server¶
Sync from one server, restore to another:
from email_profile import Email, StorageSQLite
storage = StorageSQLite("./backup.db")
# Step 1: sync from source server
with Email("user@old-server.com", "password") as source:
source.sync()
# Step 2: restore to target server
with Email("user@new-server.com", "password", storage=storage) as target:
count = target.restore()
print(f"Migrated {count} emails")
What gets restored?¶
| Data | Restored? |
|---|---|
| Email content (RFC822) | Yes |
| Mailbox/folder | Yes (created if missing) |
| Flags (read/unread, flagged) | Yes |
| Original date | Yes (from Date header) |
| IMAP UID | No (new UID assigned by server) |