@gnidreve/classic-imap-smtp-mcp 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/llms.txt ADDED
@@ -0,0 +1,262 @@
1
+ # classic-imap-smtp-mcp — LLM Reference
2
+
3
+ > This file is the machine-optimized counterpart to `README.md`. It exists so a consuming LLM (e.g. an AI assistant helping a user install classic-imap-smtp-mcp, or another agent that will call classic-imap-smtp-mcp's tools) can ingest the essential information in one pass.
4
+ >
5
+ > Human readers should prefer `README.md`. Coding agents working on the codebase should use `AGENTS.md`.
6
+
7
+ ---
8
+
9
+ ## What classic-imap-smtp-mcp is
10
+
11
+ A local-only MCP (Model Context Protocol) server that exposes a full mail client's worth of IMAP and SMTP operations as tools. Provider-agnostic. License TBD (set before v1.0 release). No telemetry. No cloud component.
12
+
13
+ ## What classic-imap-smtp-mcp is NOT
14
+
15
+ - **Not OAuth-based.** This MCP implements classic IMAP/SMTP with password-based authentication (App-Passwords supported). It does not implement OAuth2/XOAUTH2. For Microsoft 365 OAuth-only setups or Gmail-OAuth-only setups, combine this MCP with a provider-specific MCP.
16
+ - Not a calendar/scheduling system
17
+ - Not an AI triage system (no preset prompts, no auto-labeling, no inbox-zero heuristics)
18
+ - Not a notification system (no desktop alerts, no webhooks, no push to Slack/Discord)
19
+ - Not a mail server (it does not host mail; it talks to existing IMAP/SMTP servers)
20
+ - Not a future-send scheduler
21
+
22
+ If a user asks for any of the above, do not pretend classic-imap-smtp-mcp does it. Suggest combining classic-imap-smtp-mcp with another MCP that specializes in that domain.
23
+
24
+ ---
25
+
26
+ ## Setup prompt (paste this into a conversation with a user)
27
+
28
+ If a user asks you to "install classic-imap-smtp-mcp" or "set up mail in my Claude/Cursor/Windsurf/VS Code", run through the following checklist with them:
29
+
30
+ 1. **Determine the client** they use: Claude Desktop, Claude Code, Cursor, Windsurf, or VS Code (Copilot/MCP).
31
+ 2. **Collect credentials.** Required: email address, password (strongly prefer App-Password where the provider supports it — Gmail, Outlook, iCloud, Yahoo all do).
32
+ 3. **Detect the provider.** If the email domain is one of the auto-detected providers (see "Auto-detected providers" below), the user only needs to supply `CLASSIC_IMAP_SMTP_USER` and `CLASSIC_IMAP_SMTP_PASS`. Otherwise also collect IMAP host/port and SMTP host/port.
33
+ 4. **Choose a safety level.** Default is full access. If the user expresses any safety concern ("I don't want it to delete things"), recommend `--safe` (no deletes) or `--readonly` (read-only).
34
+ 5. **Write the client config** using the appropriate JSON snippet (see "Client snippets" below).
35
+ 6. **Restart the client** so it picks up the new MCP server.
36
+ 7. **Verify** by asking the user to prompt "list my email folders" — this should trigger `imap_list_mailboxes`.
37
+
38
+ If the user wants multiple accounts, instruct them to run `npx classic-imap-smtp-mcp init` to scaffold the TOML config and then edit it. The env-var path is single-account only.
39
+
40
+ ---
41
+
42
+ ## Auto-detected providers
43
+
44
+ For these email domains, only `CLASSIC_IMAP_SMTP_USER` + `CLASSIC_IMAP_SMTP_PASS` are required. Host/port are filled in automatically:
45
+
46
+ - gmail.com (Google) — IMAP imap.gmail.com:993, SMTP smtp.gmail.com:465 — App-Password required
47
+ - outlook.com, hotmail.com, live.com (Microsoft) — IMAP outlook.office365.com:993, SMTP smtp.office365.com:587 STARTTLS — App-Password required
48
+ - icloud.com, me.com, mac.com (Apple) — IMAP imap.mail.me.com:993, SMTP smtp.mail.me.com:587 STARTTLS — App-Password required
49
+ - yahoo.com, ymail.com (Yahoo) — IMAP imap.mail.yahoo.com:993, SMTP smtp.mail.yahoo.com:465 — App-Password required
50
+ - fastmail.com — IMAP imap.fastmail.com:993, SMTP smtp.fastmail.com:465 — App-Password required
51
+ - posteo.de — IMAP posteo.de:993, SMTP posteo.de:465
52
+ - mailbox.org — IMAP imap.mailbox.org:993, SMTP smtp.mailbox.org:465
53
+ - gmx.com, gmx.de, gmx.net — IMAP imap.gmx.net:993, SMTP mail.gmx.net:465
54
+ - web.de — IMAP imap.web.de:993, SMTP smtp.web.de:587 STARTTLS
55
+ - proton.me, protonmail.com — requires ProtonMail Bridge running locally; IMAP 127.0.0.1:1143, SMTP 127.0.0.1:1025
56
+
57
+ ---
58
+
59
+ ## Client snippets
60
+
61
+ ### Claude Desktop
62
+
63
+ File: `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows).
64
+
65
+ ```json
66
+ {
67
+ "mcpServers": {
68
+ "mail": {
69
+ "command": "npx",
70
+ "args": ["-y", "classic-imap-smtp-mcp"],
71
+ "env": {
72
+ "CLASSIC_IMAP_SMTP_USER": "<EMAIL>",
73
+ "CLASSIC_IMAP_SMTP_PASS": "<APP_PASSWORD>",
74
+ "CLASSIC_IMAP_SMTP_IMAP_HOST": "<IMAP_HOST_IF_NOT_AUTODETECTED>",
75
+ "CLASSIC_IMAP_SMTP_SMTP_HOST": "<SMTP_HOST_IF_NOT_AUTODETECTED>"
76
+ }
77
+ }
78
+ }
79
+ }
80
+ ```
81
+
82
+ ### Claude Code
83
+
84
+ ```bash
85
+ claude mcp add mail \
86
+ -e CLASSIC_IMAP_SMTP_USER=<EMAIL> \
87
+ -e CLASSIC_IMAP_SMTP_PASS=<APP_PASSWORD> \
88
+ -- npx -y classic-imap-smtp-mcp
89
+ ```
90
+
91
+ ### Cursor
92
+
93
+ File: `~/.cursor/mcp.json`
94
+
95
+ ```json
96
+ {
97
+ "mcpServers": {
98
+ "mail": {
99
+ "command": "npx",
100
+ "args": ["-y", "classic-imap-smtp-mcp"],
101
+ "env": { "CLASSIC_IMAP_SMTP_USER": "<EMAIL>", "CLASSIC_IMAP_SMTP_PASS": "<APP_PASSWORD>" }
102
+ }
103
+ }
104
+ }
105
+ ```
106
+
107
+ ### Windsurf
108
+
109
+ File: `~/.codeium/windsurf/mcp_config.json` — same structure as Cursor.
110
+
111
+ ### VS Code (GitHub Copilot MCP)
112
+
113
+ File: workspace `.vscode/mcp.json` or user `settings.json` under the `mcp` key:
114
+
115
+ ```json
116
+ {
117
+ "servers": {
118
+ "mail": {
119
+ "type": "stdio",
120
+ "command": "npx",
121
+ "args": ["-y", "classic-imap-smtp-mcp"],
122
+ "env": { "CLASSIC_IMAP_SMTP_USER": "<EMAIL>", "CLASSIC_IMAP_SMTP_PASS": "<APP_PASSWORD>" }
123
+ }
124
+ }
125
+ }
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Full tool catalog (36 tools)
131
+
132
+ Each tool's full Zod schema is exposed via `tools/list` in the MCP protocol. The summary below is enough to choose the right tool.
133
+
134
+ ### IMAP — Read
135
+
136
+ | Tool | Purpose | Key inputs |
137
+ |---|---|---|
138
+ | `imap_list_mailboxes` | Enumerate folders with special-use flags | `account?`, `subscribed_only?` |
139
+ | `imap_status_mailbox` | Get counts without SELECT | `mailbox`, `account?` |
140
+ | `imap_list_messages` | Paginated message list (envelope only) | `mailbox`, `page?`, `page_size?`, `account?` |
141
+ | `imap_get_message` | Full parsed message + attachment metadata | `uid`, `mailbox`, `account?` |
142
+ | `imap_get_message_headers` | Headers only | `uid`, `mailbox`, `account?` |
143
+ | `imap_get_message_raw` | RFC-822 raw source | `uid`, `mailbox`, `account?` |
144
+ | `imap_get_messages_bulk` | Up to N UIDs in one call | `uids[]`, `mailbox`, `account?` |
145
+ | `imap_search` | Full RFC-3501 SEARCH builder | `mailbox`, `criteria` (structured), `account?` |
146
+ | `imap_download_attachment` | Extract a specific MIME part | `uid`, `mailbox`, `part_id` or `filename`, `save_path?`, `account?` |
147
+ | `imap_get_thread` | Reconstruct conversation via References | `uid`, `mailbox`, `account?` |
148
+ | `imap_get_quota` | RFC-2087 quota info | `mailbox?`, `account?` |
149
+ | `imap_check_capabilities` | List server CAPABILITY | `account?` |
150
+
151
+ ### IMAP — Write
152
+
153
+ | Tool | Purpose | Key inputs |
154
+ |---|---|---|
155
+ | `imap_mark_message` | STORE flags on/off | `uid`, `mailbox`, `add[]?`, `remove[]?`, `account?` |
156
+ | `imap_bulk_mark` | Bulk STORE | `uids[]`, `mailbox`, `add[]?`, `remove[]?`, `account?` |
157
+ | `imap_move_message` | MOVE (RFC 6851) | `uid`, `from_mailbox`, `to_mailbox`, `account?` |
158
+ | `imap_copy_message` | COPY | `uid`, `from_mailbox`, `to_mailbox`, `account?` |
159
+ | `imap_bulk_move` | Bulk MOVE | `uids[]`, `from_mailbox`, `to_mailbox`, `account?` |
160
+ | `imap_append_message` | APPEND a message (drafts, import) | `mailbox`, `rfc822` or structured fields, `flags[]?`, `account?` |
161
+ | `imap_expunge` | EXPUNGE | `mailbox`, `account?` |
162
+ | `imap_delete_message` | STORE \Deleted, optional EXPUNGE | `uid`, `mailbox`, `expunge?`, `account?` |
163
+
164
+ ### IMAP — Mailbox CRUD
165
+
166
+ | Tool | Purpose | Key inputs |
167
+ |---|---|---|
168
+ | `imap_create_mailbox` | CREATE | `mailbox`, `account?` |
169
+ | `imap_delete_mailbox` | DELETE | `mailbox`, `account?` |
170
+ | `imap_rename_mailbox` | RENAME | `from`, `to`, `account?` |
171
+ | `imap_subscribe_mailbox` | SUBSCRIBE | `mailbox`, `account?` |
172
+ | `imap_unsubscribe_mailbox` | UNSUBSCRIBE | `mailbox`, `account?` |
173
+
174
+ ### SMTP
175
+
176
+ | Tool | Purpose | Key inputs |
177
+ |---|---|---|
178
+ | `smtp_send` | Send a new message | `to[]`, `subject`, `text?`, `html?`, `cc[]?`, `bcc[]?`, `attachments[]?`, `inline_images[]?`, `headers?`, `save_to_sent?` (default true), `sent_mailbox?`, `account?` |
179
+ | `smtp_reply` | Reply with correct threading | `original_uid`, `original_mailbox`, `text?`, `html?`, `reply_all?`, `include_original?`, `save_to_sent?`, `sent_mailbox?`, `account?` |
180
+ | `smtp_forward` | Forward a message | `original_uid`, `original_mailbox`, `to[]`, `text?`, `as_attachment?`, `save_to_sent?`, `sent_mailbox?`, `account?` |
181
+ | `smtp_verify_connection` | Health check | `account?` |
182
+ | `smtp_send_raw` | Send a pre-formed RFC-822 | `rfc822`, `save_to_sent?`, `sent_mailbox?`, `account?` |
183
+
184
+ ### Account-Management
185
+
186
+ | Tool | Purpose | Key inputs |
187
+ |---|---|---|
188
+ | `account_list` | List configured accounts (masked) | — |
189
+ | `account_add` | Add a new account to config | `name`, `user`, `pass`, `imap_host?`, `smtp_host?`, ... |
190
+ | `account_update` | Modify an existing account (e.g. new app-password) | `name`, fields to change |
191
+ | `account_delete` | Remove an account from config | `name` |
192
+
193
+ ### Meta — server introspection
194
+
195
+ | Tool | Purpose | Key inputs |
196
+ |---|---|---|
197
+ | `meta_health` | IMAP + SMTP reachability, latency, capabilities | `account?` |
198
+ | `meta_server_info` | Active tools, active mode, version | — |
199
+
200
+ ---
201
+
202
+ ## Feature flags & tool selection
203
+
204
+ All switches are CLI args (never env vars). Tools are registered conditionally at startup.
205
+
206
+ **Four feature flags (coarse):**
207
+ - `--safe` — removes delete tools (`imap_delete_message`, `imap_expunge`, `imap_delete_mailbox`); sending/moving/marking still work
208
+ - `--readonly` — read-only: all writing IMAP ops + SMTP send removed; `smtp_verify_connection` and `account_list` remain
209
+ - `--no-imap` — removes all IMAP tools
210
+ - `--no-smtp` — removes all SMTP tools
211
+
212
+ `--safe` + `--readonly` combine (readonly is stricter, wins). `--no-imap` + `--no-smtp` together = empty server → startup error.
213
+
214
+ **Granular (expert mode), prefix wildcards supported:**
215
+ - `--allow-tools=<csv>` — explicitly enable tools; **overrides feature flags** (brings tools back)
216
+ - `--deny-tools=<csv>` — explicitly remove tools; **wins over everything**, including allow
217
+
218
+ Wildcards: `imap_*`, `smtp_*`, `account_*`, `meta_*`, `imap_delete_*`, `imap_bulk_*`, etc.
219
+
220
+ **Cascade (coarse → fine, fine wins):** feature flags set the base → `--allow-tools` overrides them → `--deny-tools` has the final word.
221
+
222
+ Examples: `--readonly --allow-tools=smtp_send` (read-only but sending allowed) · `--deny-tools=account_*` (no account management) · `--allow-tools=imap_* --deny-tools=imap_delete_*` (all IMAP except deletes).
223
+
224
+ ---
225
+
226
+ ## How to call classic-imap-smtp-mcp's tools (for consuming agents)
227
+
228
+ classic-imap-smtp-mcp follows the standard MCP tool-call contract. Pseudo-flow:
229
+
230
+ 1. `tools/list` returns the currently registered subset (depends on the active flags).
231
+ 2. Each tool has a JSON Schema (derived from Zod). Validate inputs client-side if possible.
232
+ 3. Errors come back as structured objects: `{ code, message, details? }`. Common codes: `AUTH_FAILED`, `MAILBOX_NOT_FOUND`, `UID_NOT_FOUND`, `RATE_LIMITED`, `TLS_ERROR`, `CONFIG_ERROR`, `IMAP_PROTOCOL_ERROR`, `SMTP_RELAY_ERROR`, `ACCOUNT_NOT_FOUND`, `ATTACHMENT_NOT_FOUND`, `PERMISSION_DENIED`.
233
+ 4. Long-running operations (bulk-move with 1000+ UIDs) may emit progress notifications.
234
+
235
+ ### Conventions worth knowing
236
+
237
+ - **UIDs are per-mailbox.** Always pass `mailbox` together with `uid`.
238
+ - **Folder names are server-native.** Use `imap_list_mailboxes` first; do not hard-code names like "Sent" or "Trash" — providers vary (`[Gmail]/Sent Mail`, `INBOX.Trash`, etc.). Special-use flags from `imap_list_mailboxes` are the safe way to find them.
239
+ - **`account` is optional** when a default account is configured. When it's set in the config, omit `account` unless the user explicitly says otherwise.
240
+ - **Attachments**: `imap_get_message` returns metadata only by default. To download a binary attachment, follow up with `imap_download_attachment`.
241
+ - **Threading**: `smtp_reply` does the right thing automatically — no need to manually construct `In-Reply-To`/`References` headers.
242
+ - **Sent copies**: send tools auto-append a copy to the Sent folder (`save_to_sent`, default true) — found via the `\Sent` special-use flag. Send and save are separate: if sending succeeds but the Sent-append fails, the result reports `savedToSent: false` plus `sentSaveError`, and the mail is still sent. There is no outbox/retry queue — a failed send is reported synchronously as `SMTP_RELAY_ERROR`.
243
+
244
+ ---
245
+
246
+ ## Troubleshooting (common user issues)
247
+
248
+ - "Login fails on Gmail" → User probably uses regular password. Direct them to https://myaccount.google.com/apppasswords.
249
+ - "Connection times out" → Likely firewall or wrong port. Default IMAP 993 (TLS), SMTP 465 (TLS) or 587 (STARTTLS).
250
+ - "Self-signed certificate" → Internal/selfhosted server. Set `CLASSIC_IMAP_SMTP_VERIFY_TLS=false` *only* if user understands the risk.
251
+ - "I don't see all the tools" → User probably applied a restrictive flag. Check the `--safe`, `--readonly`, `--no-imap`, `--no-smtp`, `--deny-tools` CLI args in the client config (these are CLI args, not env vars).
252
+ - "Folder not found" → User passed a name like `Sent`; the server may name it differently. Run `imap_list_mailboxes` first.
253
+
254
+ ---
255
+
256
+ ## Versioning
257
+
258
+ Semantic Versioning. `0.x.y` until API stabilizes. Tool names and config keys are stable within a major version.
259
+
260
+ ## License
261
+
262
+ TBD (set before v1.0 release).
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@gnidreve/classic-imap-smtp-mcp",
3
+ "version": "0.3.0",
4
+ "description": "A complete classic IMAP/SMTP MCP server. Everything a good mail client does — no OAuth, no cloud lock-in, no scope creep.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "keywords": [
8
+ "mcp",
9
+ "model-context-protocol",
10
+ "imap",
11
+ "smtp",
12
+ "email",
13
+ "mail",
14
+ "mailclient",
15
+ "claude",
16
+ "ai"
17
+ ],
18
+ "homepage": "https://github.com/Gnidreve/classic-imap-smtp-mcp#readme",
19
+ "bugs": {
20
+ "url": "https://github.com/Gnidreve/classic-imap-smtp-mcp/issues"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/Gnidreve/classic-imap-smtp-mcp.git"
25
+ },
26
+ "bin": {
27
+ "classic-imap-smtp-mcp": "dist/main.js"
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "README.md",
32
+ "llms.txt",
33
+ "LICENSE"
34
+ ],
35
+ "engines": {
36
+ "node": ">=20"
37
+ },
38
+ "dependencies": {
39
+ "@modelcontextprotocol/sdk": "^1.29.0",
40
+ "imapflow": "^1.0.0",
41
+ "mailparser": "^3.7.0",
42
+ "nodemailer": "^6.9.0",
43
+ "pino": "^9.0.0",
44
+ "smol-toml": "^1.3.0",
45
+ "zod": "^3.23.0"
46
+ },
47
+ "devDependencies": {
48
+ "@biomejs/biome": "^1.9.0",
49
+ "@types/mailparser": "^3.4.0",
50
+ "@types/node": "^20.0.0",
51
+ "@types/nodemailer": "^6.4.0",
52
+ "lefthook": "^1.7.0",
53
+ "pino-pretty": "^11.0.0",
54
+ "tsup": "^8.0.0",
55
+ "tsx": "^4.0.0",
56
+ "typescript": "^5.5.0",
57
+ "vitest": "^2.0.0"
58
+ },
59
+ "scripts": {
60
+ "build": "tsup",
61
+ "dev": "tsx src/bin/main.ts",
62
+ "start": "node dist/bin/main.js",
63
+ "typecheck": "tsc --noEmit",
64
+ "lint": "biome check src test",
65
+ "lint:fix": "biome check --write src test",
66
+ "format": "biome format --write src test",
67
+ "test": "vitest run",
68
+ "test:watch": "vitest",
69
+ "test:integration": "vitest run --config vitest.integration.config.ts"
70
+ }
71
+ }