First Steps¶
1. Connect¶
The simplest way to connect is with auto-discovery — just your email and password.
# Code above omitted 👆
# Auto-discovery (recommended)
with Email("user@gmail.com", "app_password") as app:
print(f"Connected to {app.server}")
print(f"Mailboxes: {app.mailboxes()}")
# Code below omitted 👇
👀 Full file preview
"""Connect to an email server."""
from email_profile import Email
def main() -> None:
# Auto-discovery (recommended)
with Email("user@gmail.com", "app_password") as app:
print(f"Connected to {app.server}")
print(f"Mailboxes: {app.mailboxes()}")
# Explicit server
with Email("imap.gmail.com", "user@gmail.com", "app_password") as app:
print(f"Connected to {app.server}")
# From environment variables (.env)
with Email.from_env() as app:
print(f"Connected as {app.user}")
if __name__ == "__main__":
main()
2. Read Emails¶
Access your inbox and iterate over messages.
# Code above omitted 👆
with Email.from_env() as app:
# Count
print(f"Total: {app.inbox.where().count()}")
# Read all
for msg in app.inbox.where().messages():
print(f"{msg.date} | {msg.from_} | {msg.subject}")
# Code below omitted 👇
👀 Full file preview
"""Read emails from INBOX."""
from email_profile import Email
def main() -> None:
with Email.from_env() as app:
# Count
print(f"Total: {app.inbox.where().count()}")
# Read all
for msg in app.inbox.where().messages():
print(f"{msg.date} | {msg.from_} | {msg.subject}")
# Read only headers (faster)
for msg in app.inbox.where().messages(mode="headers"):
print(f"{msg.subject}")
# Read first 10
for msg in app.inbox.where().messages(chunk_size=10):
print(f"{msg.uid}: {msg.subject}")
break
if __name__ == "__main__":
main()
3. Search¶
Use the Q builder for composable queries.
# Code above omitted 👆
def main() -> None:
with Email.from_env() as app:
# Shortcuts
print(f"Unread: {app.unread().count()}")
print(f"Recent 7 days: {app.recent(days=7).count()}")
print(f"Search 'invoice': {app.search('invoice').count()}")
# Q builder (composable)
q = Q.subject("meeting") & Q.unseen()
print(f"Unseen meetings: {app.inbox.where(q).count()}")
# Code below omitted 👇
👀 Full file preview
"""Search emails with Q builder and Query."""
from datetime import date
from email_profile import Email, Q, Query
def main() -> None:
with Email.from_env() as app:
# Shortcuts
print(f"Unread: {app.unread().count()}")
print(f"Recent 7 days: {app.recent(days=7).count()}")
print(f"Search 'invoice': {app.search('invoice').count()}")
# Q builder (composable)
q = Q.subject("meeting") & Q.unseen()
print(f"Unseen meetings: {app.inbox.where(q).count()}")
# OR
q = Q.from_("alice@x.com") | Q.from_("bob@x.com")
print(f"From Alice or Bob: {app.inbox.where(q).count()}")
# NOT
q = ~Q.seen()
print(f"Not seen: {app.inbox.where(q).count()}")
# Date range
q = Q.since(date(2025, 1, 1)) & Q.before(date(2025, 12, 31))
print(f"Year 2025: {app.inbox.where(q).count()}")
# Size filter
q = Q.larger(1_000_000)
print(f"Larger than 1MB: {app.inbox.where(q).count()}")
# Query (Pydantic, validated)
query = Query(subject="report", unseen=True, since=date(2025, 1, 1))
print(f"Query: {app.inbox.where(query).count()}")
# Check if exists
if app.inbox.where(Q.unseen()).exists():
print("You have unread emails!")
if __name__ == "__main__":
main()
4. Send¶
Send emails via SMTP.
# Code above omitted 👆
with Email.from_env() as app:
# Simple send
app.send(
to="recipient@example.com",
subject="Hello",
body="Hi there!",
)
# Code below omitted 👇
👀 Full file preview
"""Send emails via SMTP."""
from email_profile import Email
def main() -> None:
with Email.from_env() as app:
# Simple send
app.send(
to="recipient@example.com",
subject="Hello",
body="Hi there!",
)
# With HTML
app.send(
to="recipient@example.com",
subject="Report",
body="See attached report.",
html="<h1>Report</h1><p>See attached.</p>",
)
# With attachments
app.send(
to=["alice@x.com", "bob@x.com"],
subject="Files",
body="Here are the files.",
attachments=["report.pdf", "data.csv"],
)
# With CC/BCC
app.send(
to="recipient@example.com",
subject="Meeting",
body="Tomorrow at 10am.",
cc="manager@example.com",
bcc="hr@example.com",
)
# Reply to an email
msg = list(app.inbox.where().messages(chunk_size=1))[0]
app.reply(msg, body="Thanks for your email!")
# Forward an email
app.forward(msg, to="colleague@example.com", body="FYI")
if __name__ == "__main__":
main()
5. Sync¶
Backup your mailbox to a local SQLite database.
# Code above omitted 👆
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")
# 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()
Full Code¶
"""Read your unread mail in 4 lines."""
from email_profile import Email
def main() -> None:
with Email.from_env() as app:
for msg in app.unread().messages():
print(f"{msg.date} {msg.from_:<40} {msg.subject}")
if __name__ == "__main__":
main()