semos-agentura-email
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)
Create a .env in this directory and configure the keys below.
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
Agent discovery and runtime keys (AGENT_HOST, LOG_LEVEL, ROUTER_LLM_*) are documented in the
root README.
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 eventset_flag: set an email's flag tomarked(follow-up),complete, ornone
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/semos/agentura/email/
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
Metadata
Release files for semos-agentura-email 1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| semos_agentura_email-1.0.1.tar.gz | 47.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| semos_agentura_email-1.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 91.3 kB
Release files / semos_agentura_email-1.0.1.tar.gz
| Download URL | semos_agentura_email-1.0.1.tar.gz |
|---|---|
| Size | 47.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8dfef6d345b7bc71a307e65f46dfc348a2a8482a32562003d393e1459444b4f2
|
|
BLAKE2b-256 checksum How to use checksums |
b48d4bb0674858bdfb294103d3591da26eebe83153167d294e61b85dfd6f3640
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","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}
|
Release files / semos_agentura_email-1.0.1-py3-none-any.whl
| Download URL | semos_agentura_email-1.0.1-py3-none-any.whl |
|---|---|
| Size | 43.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4e262d22cc230ab3fb46547ecf29a90c90afa06e99c7ced47548dc9e0b9780ef
|
|
BLAKE2b-256 checksum How to use checksums |
d029d4b722cad39f73e2fbac0721d20f06dbb63f37d6d77b2bd7bb0c6445fd42
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","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}
|