An open API service indexing awesome lists of open source software.

https://github.com/linux-profile/email-profile

πŸ“© Email Profile
https://github.com/linux-profile/email-profile

Last synced: 2 months ago
JSON representation

πŸ“© Email Profile

Awesome Lists containing this project

README

          

# email-profile

[![PyPI](https://img.shields.io/pypi/v/email-profile)](https://pypi.org/project/email-profile/)
[![Python](https://img.shields.io/pypi/pyversions/email-profile)](https://pypi.org/project/email-profile/)
[![Tests](https://img.shields.io/github/actions/workflow/status/linux-profile/email-profile/test.yml?branch=develop&label=tests)](https://github.com/linux-profile/email-profile/actions)
[![License](https://img.shields.io/github/license/linux-profile/email-profile)](LICENSE)
[![Downloads](https://img.shields.io/pypi/dm/email-profile)](https://pypi.org/project/email-profile/)

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.

```python
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.

---

- **Documentation**: [linux-profile.github.io/email-profile](https://linux-profile.github.io/email-profile/)
- **Source Code**: [github.com/linux-profile/email-profile](https://github.com/linux-profile/email-profile)
- **PyPI**: [pypi.org/project/email-profile](https://pypi.org/project/email-profile/)

---

## Install

```bash
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:

```python
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

```python
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:

```python
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:

```python
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:

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

### Send Emails

Send, reply, and forward β€” with automatic SMTP discovery:

```python
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="

Report

",
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.

```python
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

```python
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.

```python
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

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

## License

MIT