Unified email client (IMAP/SMTP + Outlook COM) with LLM agent and archive
Project description
email-agent
Unified email client with LLM agent. Supports IMAP/SMTP, Outlook COM, CalDAV, and Microsoft Graph API backends.
Backends
| Backend | Calendar | Platform | Provider | |
|---|---|---|---|---|
| COM | Yes | Yes | Windows only | M365/Exchange |
| IMAP/SMTP | Yes | No | Any | Any |
| CalDAV | No | Yes | Any | Google, Nextcloud, iCloud |
| Graph API | No | No | Any | M365 (Phase 3) |
Email and calendar backends are independent (for example, IMAP for email plus CalDAV for calendar).
Auto-detection priority:
- Explicit
BACKEND=com|imap|graphoverrides IMAP_HOST+AZURE_CLIENT_ID+EMAIL_ADDRESS→ IMAPGRAPH_CLIENT_ID→ Graph API- Windows → COM
Setup
uv sync # base (IMAP + LLM agent)
uv sync --extra com # + Outlook COM (Windows)
Copy .env.example to .env and configure.
IMAP/SMTP (any OS)
AZURE_CLIENT_ID=your-azure-app-client-id
AZURE_TENANT_ID=your-tenant-id
EMAIL_ADDRESS=user@example.com
IMAP_HOST=outlook.office365.com
SMTP_HOST=smtp.office365.com
COM (Windows, no config needed)
Outlook must be running. Auto-detected on Windows if no IMAP config is set.
@mailgent agent
MODEL=anthropic/claude-sonnet-4-5
AZURE_API_KEY=your-api-key
AZURE_API_BASE=https://your-endpoint.openai.azure.com
CLI
uv run python run.py # show help
# Email
uv run python run.py search-emails <query>
uv run python run.py read-email <query>
uv run python run.py read-email <query> --save-att
uv run python run.py draft <to> <subject> <body> [--cc=...] [--att=file1,file2]
uv run python run.py send <to> <subject> <body>
# Calendar
uv run python run.py events [days]
uv run python run.py free-slots [days]
uv run python run.py create-event <subject> <start> <end>
# @mailgent agent
uv run python run.py agent [interval] # polling loop (default 30s)
uv run python run.py agent-once # process pending and exit
# Archive
uv run python run.py archive # incremental dump to SQLite
uv run python run.py archive-stats
uv run python run.py archive-search <query>
@mailgent
Write @mailgent: in a draft or incoming email to trigger the LLM agent:
Dear colleague,
@mailgent: What are my free slots next week?
Best regards
The agent processes the prompt, calls tools (search emails, check calendar, etc.), and inserts the response directly below the prompt with a unique ID:
Dear colleague,
@mailgent[a1b2c3d4]: What are my free slots next week?
------------ mailgent[a1b2c3d4] ------------
Monday: 10:00-12:00, 14:00-17:00
Tuesday: 8:00-10:00, 13:00-17:00
------------ mailgent[a1b2c3d4] ------------
Best regards
Re-run: Delete the response block and remove the [id] from the prompt.
Multiple prompts per email are supported, and each gets its own ID.
Tools available to @mailgent
search_emails: search by subjectread_email: read full email contentlist_events: calendar events for next N daysfree_slots: free meeting slotscreate_draft: create email draftdraft_reply/send_reply: reply to an emaildraft_event/send_event: create calendar event
Config
MAILGENT_TAG=@mailgent
MAILGENT_MODEL=anthropic/claude-sonnet-4-5 # or use MODEL=
MAILGENT_AUTO_REPLY=false # reply to inbox emails
MAILGENT_AUTO_SEND=false # send replies immediately
MAILGENT_TRUSTED_REPLY=*@company.com # auto-reply trust list
MAILGENT_TRUSTED_SEND=me@company.com # auto-send trust list
Tests
uv run pytest tests/ -v # all tests
uv run pytest tests/test_backend.py -v # unit tests (mocked, no backend needed)
uv run pytest tests/test_integration.py -v # integration tests (needs real backend)
Architecture
src/email_agent/
config.py Settings (Pydantic BaseSettings)
models.py EmailMessage, Attachment, EventInfo
exceptions.py Exception hierarchy
auth.py OAuth2 (MSAL device code flow)
imap_client.py IMAP read/search/draft
smtp_client.py SMTP send
client.py MailClient facade (IMAP + SMTP)
backend.py EmailBackend + CalendarBackend protocols, IMAPBackend, COMBackend, factory
com_client.py Outlook COM wrapper (Windows)
tools.py LLM tool definitions + executor
mailgent.py @mailgent agent loop
formatting.py Markdown ↔ plain/HTML conversion
archive.py Incremental SQLite archive
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file semos_agentura_email-0.5.0.tar.gz.
File metadata
- Download URL: semos_agentura_email-0.5.0.tar.gz
- Upload date:
- Size: 46.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c0c51f0d8c696744e786ac86b55ebf191640a1b2486766f123d2fa5c08fd0f4d
|
|
| MD5 |
5e1b39da02c5bd23f54c44c31d27cb7f
|
|
| BLAKE2b-256 |
eca5bc2f579c49f3b1ad4b7b6aaea2b949e3769e4db2efa626b6d58eb4de6022
|
File details
Details for the file semos_agentura_email-0.5.0-py3-none-any.whl.
File metadata
- Download URL: semos_agentura_email-0.5.0-py3-none-any.whl
- Upload date:
- Size: 43.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5a0e6afd4b86cad629c809893774d592ccfc60445c3a2907062bb7c7a2c1187f
|
|
| MD5 |
e751ec093b7849174cf5caee9bd04b88
|
|
| BLAKE2b-256 |
77bfd06ded032960a8ecb3e7b9d768645923288efa1521b84395cf375773bbea
|