Skip to main content

The simplest way to work with email in Python. Read, search, send, sync, backup and restore — IMAP + SMTP in one library.

Project description

email-profile

PyPI Python Tests License Downloads

The simplest way to work with email in Python. No boilerplate, no low-level IMAP commands, no headaches.

Just connect, read, search, send, backup, and restore — with one class.

from email_profile import Email

with Email("user@gmail.com", "app_password") as app:
    for msg in app.inbox.where().messages():
        print(f"{msg.date} | {msg.from_} | {msg.subject}")

That's it. No server configuration needed — email-profile auto-discovers your IMAP server from your email address.



Install

pip install email-profile

Why email-profile?

Most Python email libraries make you deal with imaplib directly, parse raw bytes, manage connections manually, and write dozens of lines just to read your inbox.

email-profile gives you a clean, human API:

  • Write Email("user@gmail.com", "pw") instead of configuring IMAP servers manually
  • Write app.inbox.where(Q.unseen()).first() instead of raw IMAP search commands
  • Write app.sync() instead of building your own backup system
  • Write app.send(to="...", subject="...", body="...") instead of constructing MIME messages

It combines IMAP + SMTP + storage + sync in a single library. No other Python package does this.

Quick Start

Connect

Three ways to connect — pick the one that fits:

from email_profile import Email

# Just email + password (auto-discovers the server)
with Email("user@gmail.com", "app_password") as app:
    print(app.mailboxes())

# From .env file (great for production)
with Email.from_env() as app:
    print(app.mailboxes())

# Explicit server (when you need full control)
with Email("imap.gmail.com", "user@gmail.com", "app_password") as app:
    print(app.mailboxes())

Read Emails

with Email.from_env() as app:
    # How many emails?
    print(app.inbox.where().count())

    # Read them
    for msg in app.inbox.where().messages():
        print(f"{msg.date} | {msg.from_} | {msg.subject}")

    # Just the first one
    msg = app.inbox.where().first()

    # Only headers (much faster for large mailboxes)
    for msg in app.inbox.where().messages(mode="headers"):
        print(msg.subject)

Search

Find exactly what you need with composable queries:

from email_profile import Email, Q
from datetime import date

with Email.from_env() as app:
    # Combine conditions with & (AND), | (OR), ~ (NOT)
    q = Q.subject("meeting") & Q.unseen()
    print(app.inbox.where(q).count())

    # From Alice or Bob
    q = Q.from_("alice@x.com") | Q.from_("bob@x.com")

    # Everything except seen emails
    q = ~Q.seen()

    # Emails from 2025, larger than 1MB
    q = Q.since(date(2025, 1, 1)) & Q.before(date(2025, 12, 31)) & Q.larger(1_000_000)

Or use validated kwargs if you prefer:

from email_profile import Query

query = Query(subject="report", unseen=True, since=date(2025, 1, 1))
query = Query(subject="report").exclude(subject="spam").or_(subject="urgent")

Built-in shortcuts for common searches:

app.unread().count()
app.recent(days=7).count()
app.search("invoice").count()

Send Emails

Send, reply, and forward — with automatic SMTP discovery:

with Email.from_env() as app:
    # Simple
    app.send(to="recipient@x.com", subject="Hello", body="Hi there!")

    # HTML + attachments + CC
    app.send(
        to=["alice@x.com", "bob@x.com"],
        subject="Report",
        body="See attached.",
        html="<h1>Report</h1>",
        attachments=["report.pdf"],
        cc="manager@x.com",
    )

    # Reply to an email (preserves threading)
    msg = app.inbox.where().first()
    app.reply(msg, body="Thanks!")

    # Forward
    app.forward(msg, to="colleague@x.com", body="FYI")

Backup & Restore

Sync your entire mailbox to a local SQLite database. Incremental — only downloads new emails. Parallel — multiple mailboxes at once. With progress bars.

with Email.from_env() as app:
    # Backup everything (compares by Message-ID, skips duplicates)
    result = app.sync()
    print(f"{result.inserted} new, {result.skipped} skipped")

    # Backup one mailbox
    result = app.sync(mailbox="INBOX")

    # Force re-download (skip duplicate check)
    result = app.sync(skip_duplicates=False)

    # Restore to server (e.g. after migrating)
    count = app.restore()
Sync demo

Mailbox Operations

with Email.from_env() as app:
    # Built-in folder shortcuts (auto-detected across languages)
    app.inbox      # INBOX
    app.sent       # Sent / Enviados / Enviadas
    app.trash      # Trash / Lixeira / Papelera
    app.drafts     # Drafts / Rascunhos
    app.spam       # Spam / Junk / Lixo Eletrônico

    # Any folder by name
    work = app.mailbox("INBOX.Work")

    # Message operations
    work.mark_seen(uid)
    work.move(uid, "INBOX.Archive")
    work.delete(uid)

Custom Storage

Storage is lazily initialized — email.db is only created when sync() or restore() is first called.

from email_profile import Email, StorageSQLite

# Default: saves to ./email.db on first sync
with Email.from_env() as app:
    app.sync()

# Custom path
with Email.from_env() as app:
    app.storage = StorageSQLite("./backup.db")
    app.sync()

Features

Feature Description
Auto-discovery Detects IMAP/SMTP servers from email domain (50+ providers)
Unified API IMAP + SMTP in a single Email class
Query Builder Composable search with Q (AND, OR, NOT) and validated Query kwargs
Sync & Restore Incremental backup to SQLite, restore to any server
Parallel Multi-threaded sync and restore with configurable workers
Progress Rich progress bars with per-mailbox status
Retry Exponential backoff on transient failures
Send Send, reply, forward with HTML, attachments, CC/BCC
Storage Pluggable storage backend (SQLite default)
Flags Read/unread, flag, delete, move, copy operations
Context Manager with Email(...) as app: for automatic cleanup

Supported Providers

Auto-discovery works out of the box. Just use your email and password — no server configuration needed.

Provider IMAP Server
Gmail imap.gmail.com
Outlook / Hotmail / Live outlook.office365.com
Yahoo imap.mail.yahoo.com
iCloud imap.mail.me.com
Zoho imap.zoho.com
ProtonMail (Bridge) 127.0.0.1:1143
AOL imap.aol.com
Yandex imap.yandex.com
Mail.ru imap.mail.ru
GMX imap.gmx.com
Hostinger imap.hostinger.com
GoDaddy imap.secureserver.net
Namecheap mail.privateemail.com
Gandi mail.gandi.net
OVH ssl0.ovh.net
Ionos (1&1) imap.ionos.com
Fastmail imap.fastmail.com
Rackspace secure.emailsrvr.com
Titan imap.titan.email
Locaweb imap.locaweb.com.br
KingHost imap.kinghost.net
UOL imap.uol.com.br
Terra imap.terra.com.br

Any server with DNS SRV or MX records is also detected automatically.

Environment Variables

EMAIL_USERNAME=user@example.com
EMAIL_PASSWORD=app_password
EMAIL_SERVER=imap.example.com  # optional, auto-discovered

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

email_profile-1.0.0.dev1.tar.gz (34.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

email_profile-1.0.0.dev1-py3-none-any.whl (45.0 kB view details)

Uploaded Python 3

File details

Details for the file email_profile-1.0.0.dev1.tar.gz.

File metadata

  • Download URL: email_profile-1.0.0.dev1.tar.gz
  • Upload date:
  • Size: 34.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for email_profile-1.0.0.dev1.tar.gz
Algorithm Hash digest
SHA256 5f8ee48852c1ca81f0ad41cba8e4f6be6a2b9cf2e6ece9a3d91686073cafbcdc
MD5 f08ff4f83e4f44b7fc0f066c5f5cf6a5
BLAKE2b-256 d67f66b2ddbbfe3eb1c29bab8fcd5e79d534d7c6118950691d2e64d8c7dfd760

See more details on using hashes here.

Provenance

The following attestation bundles were made for email_profile-1.0.0.dev1.tar.gz:

Publisher: python-publish-pypi.yml on linux-profile/email-profile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file email_profile-1.0.0.dev1-py3-none-any.whl.

File metadata

File hashes

Hashes for email_profile-1.0.0.dev1-py3-none-any.whl
Algorithm Hash digest
SHA256 5180eef74082dd2c8687da60677199848f90f9069f19565d191eb866c6bab087
MD5 17a594eaa8e04b2da7158210fdde2d78
BLAKE2b-256 d88f4676ab3c083cec4be7e84e9e70244b4d2a549dcd12b5d9476cf9386d74a8

See more details on using hashes here.

Provenance

The following attestation bundles were made for email_profile-1.0.0.dev1-py3-none-any.whl:

Publisher: python-publish-pypi.yml on linux-profile/email-profile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page