43 Commits
Author SHA1 Message Date
0xKandGitHub 604fb38937 Merge pull request #15 from kacperkwapisz/add-mit-license
docs: add MIT license
2026-06-25 01:04:26 +02:00
Kacper Kwapisz 93e3de3e84 docs: add MIT license 2026-06-25 01:02:57 +02:00
Kacper Kwapisz 23d4b1fc79 Merge remote-tracking branch 'origin/main' into fix/issue-5-watcher-uid-tracking 2026-04-29 11:16:20 +02:00
Kacper Kwapisz c88ea40459 Persist watcher UID cursor across reconnects
The IDLE watcher previously re-baselined last_seen_uid on every
reconnect (e.g. after iCloud's unsolicited FETCH FLAGS responses
during IDLE caused idle_check to raise). Mail that arrived during the
short disconnect window had a UID below the new baseline and was
silently dropped, so Poke never saw it.

Hoist last_seen_uid and last_uidvalidity to the outer reconnect loop
so the cursor survives transient disconnects. Reset only on first run
or when UIDVALIDITY changes (which means the server has reassigned
UIDs and the previous cursor is meaningless).

Apply the same fix to _poll_folder via a shared mutable cursor dict so
non-IDLE servers also retain their cursor across poll-error reconnects.

Fixes #5
2026-04-29 09:30:15 +02:00
Kacper Kwapisz 68c40055e7 Merge remote-tracking branch 'origin/main' into fix/issue-5-watcher-uid-tracking 2026-04-29 09:28:08 +02:00
Kacper Kwapisz 83a3c482ec Skip MCP_API_KEY generation in tunnel mode
start.sh previously generated and persisted an MCP_API_KEY to .env
unconditionally on first run. In tunnel mode (POKE_TUNNEL=1, the
default) the local server runs unauthenticated and the Poke tunnel
handles auth — generating a key there is at best useless and at worst
overwrites the user's pre-set key, causing 421 errors at the tunnel.

Move .env loading and POKE_TUNNEL resolution above the generation
block, and skip generation entirely when POKE_TUNNEL=1. Re-source .env
after a successful generation so the rest of the script sees the new
value.

Fixes #9
2026-04-29 09:27:59 +02:00
Kacper Kwapisz af796d8583 Send IMAP ID after login for providers that require it (netease)
Some providers (notably netease 163.com / 126.com / yeah.net) reject
clients that don't issue an RFC 2971 ID command after login. Send a
minimal client identification when the server advertises the ID
capability. Failures are logged at debug and never break login.

Fixes #10
2026-04-29 09:25:59 +02:00
Kacper Kwapisz 5f049c691a Apply ruff format 2026-04-29 09:18:55 +02:00
Kacper Kwapisz c543ed9c47 Add list_accounts tool and require account_id on all email tools
- New list_accounts MCP tool: cheap inbox discovery with no IMAP I/O
- account_id is now required on all 11 per-account tools (no silent
  fallback to first configured account)
- resolve_account: whitespace-tolerant, case-insensitive id matching,
  ambiguity detection on email-address fallback, clear errors that
  point agents at list_accounts
- get_server_info: description clarifies it does live IMAP checks
- Version bumped to 1.1.0
- README: tool count 12 -> 13, breaking-change note, account_id
  requirement called out
2026-04-29 09:12:00 +02:00
Kacper Kwapisz 1d4fe9c4cf Fix emails marked as read despite mark_as_read: false
Open IMAP folder in readonly mode when mark_as_read is false,
preventing FETCH RFC822 from implicitly setting the \Seen flag.
2026-03-25 16:46:10 +01:00
Kacper Kwapisz 93b6873925 Add GitHub Releases and version-based OTA updates
- Add __version__ = "0.1.0" to src/server.py
- Add release.yml workflow to create GitHub Releases on v* tags
- Refactor start.sh OTA to use GitHub Releases API instead of commit SHAs
2026-03-25 15:10:23 +01:00
Kacper Kwapisz 7ac6531248 Fix ruff formatting 2026-03-25 14:49:21 +01:00
Kacper Kwapisz 5a6ae3e94f Add mark_as_read config option to preserve email read status
Emails forwarded to Poke are no longer marked as read by default,
so users can continue using read/unread status to organize their
inbox. Set mark_as_read: true (global or per-account) to restore
the previous behavior.

Closes #5
2026-03-25 14:47:42 +01:00
Kacper Kwapisz 7d38b7ed81 Fix detect_drafts_folder using non-existent imapclient.DRAFTS constant
imapclient.DRAFTS does not exist (only imapclient.DRAFT, which is a
message flag, not a folder attribute). Replaced with direct list_folders
iteration checking for the \Drafts special-use flag, matching the
approach used by detect_archive_folder.
2026-03-24 16:16:26 +01:00
Kacper Kwapisz e457f9576c Add .DS_Store to .gitignore 2026-03-24 15:55:58 +01:00
Kacper Kwapisz 2343072c7d Add rate limiting, route filtering, and webhook payload improvements
- Add DropNonMCPRoutes middleware to return empty 404 for non-MCP paths
- Add per-IP sliding window rate limiter with separate GET/POST buckets
- Include account_id and from_address in webhook forwarding payload
- Fix IDLE watcher to always check UNSEEN instead of filtering by EXISTS
- Track seen UIDs to avoid re-forwarding on subsequent IDLE cycles
- Switch to uvicorn.run() with Starlette middleware stack
2026-03-24 15:54:44 +01:00
Kacper Kwapisz 9fe13e5e97 Add update check on start.sh launch
Compares local HEAD against latest main on GitHub and prints a notice
if a newer version is available.
2026-03-23 19:35:05 +01:00
Kacper Kwapisz fef9157c4a Fix GET /mcp 405 log spam and resolve_account email matching
Add a custom GET /mcp health route so health checks and client polling
return 200 instead of flooding logs with 405. Also allow resolve_account
to match by email address (from_address, imap_username, smtp_username)
in addition to account ID.
2026-03-23 19:33:51 +01:00
Kacper Kwapisz bbee0acb13 Move AI agent setup to Quick Start as the primary onboarding path 2026-03-23 19:16:20 +01:00
Kacper Kwapisz 420428e513 Remove one-click deploy buttons, Deployment section, and render.yaml
Non-technical users are covered by the AI agent setup prompt.
Technical users can follow Setup or Docker sections directly.
2026-03-23 19:11:24 +01:00
Kacper Kwapisz 6e1a487676 Use fenced code block for AI agent prompt so GitHub shows copy button 2026-03-23 19:09:48 +01:00
Kacper Kwapisz 2950e5d82c Add AI agent setup prompt, start.sh launcher, and container resource limits
Adds a copy-pasteable prompt for non-technical users to set up poke-mail
via their AI coding agent, a start.sh script that loads .env, activates
the virtualenv, starts the server, and tunnels to Poke, and recommended
container resource limits for orchestrators.
2026-03-23 19:08:31 +01:00
Kacper Kwapisz b3a5cd4c5b Switch webhook endpoint to Poke SDK's /inbound/api-message 2026-03-23 16:38:53 +01:00
Kacper Kwapisz df2dc57600 Fix GHCR image URL to use actual repo owner 2026-03-23 16:29:23 +01:00
Kacper Kwapisz 81945732d1 Update config examples to show iCloud and custom SMTP instead of Gmail 2026-03-23 14:24:29 +01:00
Kacper Kwapisz 2f7853f2bf Add one-click deploy buttons for Render and Railway
Update render.yaml to use Docker runtime with IMAP env vars so the
deploy button prompts users for credentials. Add Railway deploy link.
2026-03-23 14:06:32 +01:00
Kacper Kwapisz a02b558654 Add from_address to README config example 2026-03-23 13:51:12 +01:00
Kacper Kwapisz 4ca7032e30 Add from_address override per account for custom domain sending
Useful for iCloud SMTP where login is @icloud.com but you send as a
custom domain. Falls back to smtp_username when not set.
2026-03-23 13:47:29 +01:00
Kacper Kwapisz 4a14d33e22 Default allow_send to false — sending must be explicitly enabled 2026-03-23 08:55:17 +01:00
Kacper Kwapisz 518aeda901 Add blocked_recipients per account to prevent sending to specific addresses 2026-03-23 08:52:59 +01:00
Kacper Kwapisz 0323eb1f7f Fix log spam: skip existing unseen on startup, silence httpx logs 2026-03-23 00:21:21 +01:00
Kacper Kwapisz 8a2d6ac8ed Add debug logging for Poke webhook auth to diagnose 401s 2026-03-23 00:20:23 +01:00
Kacper Kwapisz 9c84ea1a91 Add create_draft tool and allow_send toggle per account
- create_draft: saves email as draft in IMAP Drafts folder
- allow_send: global config toggle (default true), overridable per account
- When sending disabled, send_email returns error suggesting create_draft
2026-03-23 00:13:35 +01:00
Kacper Kwapisz 6e9f1ca617 Fix NoneType encode error in search_emails address formatting 2026-03-23 00:00:47 +01:00
Kacper Kwapisz dc7d379334 Fix healthcheck: expect 405 from GET /mcp (MCP is POST-only) 2026-03-22 22:11:27 +01:00
Kacper Kwapisz 8a0abba80c Make SMTP config optional, falls back to IMAP host/credentials 2026-03-22 22:06:48 +01:00
Kacper Kwapisz d5e80f164e Quote YAML values containing colons in config example 2026-03-22 22:00:28 +01:00
Kacper Kwapisz 48b3f3816f Change default port to 3000 2026-03-22 21:55:49 +01:00
Kacper Kwapisz fc9a2bb8f8 Fix lint: remove unused imports, apply ruff formatting 2026-03-22 21:52:37 +01:00
Kacper Kwapisz 96d5e7d4e3 Use semver-only tags for Docker images, drop branch/sha tags 2026-03-22 21:50:36 +01:00
Kacper Kwapisz 385202022e Add :latest tag to Docker image on main branch pushes 2026-03-22 21:49:44 +01:00
Kacper Kwapisz c034589666 Fix CI workflow YAML syntax: escape curly braces in python command 2026-03-22 21:47:40 +01:00
Kacper Kwapisz eb76dbb489 Initial release: IMAP/SMTP email bridge MCP server
- 11 MCP tools: search, read, send, archive, move, mark emails + folder management
- IMAP IDLE watcher with polling fallback, forwards new emails to Poke webhook
- Bearer token auth (MCP_API_KEY) for securing the server
- Multi-account support via config.yml
- Docker + GitHub Actions CI/CD (lint, build, push to GHCR)
2026-03-22 21:46:14 +01:00