owlpost 0.1.0__tar.gz

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.
@@ -0,0 +1,40 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ *.egg-info/
8
+ *.egg
9
+ build/
10
+ dist/
11
+ wheels/
12
+ .eggs/
13
+
14
+ # Virtual environments
15
+ .venv/
16
+ venv/
17
+ env/
18
+ ENV/
19
+
20
+ # uv
21
+ .uv/
22
+
23
+ # Tools
24
+ .pytest_cache/
25
+ .mypy_cache/
26
+ .ruff_cache/
27
+ .coverage
28
+ htmlcov/
29
+
30
+ # Editors
31
+ .vscode/
32
+ .idea/
33
+ *.swp
34
+ .DS_Store
35
+
36
+ # Secrets — never commit real credentials
37
+ accounts.toml
38
+ *.local.toml
39
+ .env
40
+ .env.*
owlpost-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sumeet Singh Mankoo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
owlpost-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,224 @@
1
+ Metadata-Version: 2.4
2
+ Name: owlpost
3
+ Version: 0.1.0
4
+ Summary: High-fidelity IMAP/SMTP MCP server for iCloud, Gmail, and other mail providers
5
+ Project-URL: Homepage, https://github.com/smankoo/owlpost
6
+ Project-URL: Repository, https://github.com/smankoo/owlpost
7
+ Project-URL: Issues, https://github.com/smankoo/owlpost/issues
8
+ Author-email: Sumeet Singh Mankoo <sumeet@mankoo.ca>
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 Sumeet Singh Mankoo
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: claude,email,gmail,icloud,imap,mcp,model-context-protocol,smtp
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Environment :: Console
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: Intended Audience :: End Users/Desktop
36
+ Classifier: License :: OSI Approved :: MIT License
37
+ Classifier: Operating System :: OS Independent
38
+ Classifier: Programming Language :: Python :: 3
39
+ Classifier: Programming Language :: Python :: 3.11
40
+ Classifier: Programming Language :: Python :: 3.12
41
+ Classifier: Programming Language :: Python :: 3.13
42
+ Classifier: Topic :: Communications :: Email
43
+ Classifier: Topic :: Communications :: Email :: Post-Office :: IMAP
44
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
45
+ Requires-Python: >=3.11
46
+ Requires-Dist: mcp>=1.2.0
47
+ Description-Content-Type: text/markdown
48
+
49
+ # owlpost
50
+
51
+ A high-fidelity IMAP/SMTP MCP server for iCloud, Gmail, and other mail
52
+ providers. Built because every other email MCP server I tried got tripped up
53
+ by real-world IMAP quirks (CRLF line endings, `RFC822` vs `BODY.PEEK[]`,
54
+ provider-specific Sent folders, multi-word search values).
55
+
56
+ owlpost is the one I actually use day-to-day from Claude Code to read,
57
+ search, follow conversations, and send mail.
58
+
59
+ ## Features
60
+
61
+ - **Multi-account** — configure as many mailboxes as you want, switch by name
62
+ - **iCloud and Gmail tested end-to-end**, with provider-specific quirks handled:
63
+ - iCloud's `RFC822` fetch returns empty bodies → uses `BODY.PEEK[]`
64
+ - iCloud's IMAP `APPEND` requires CRLF line endings → all outbound mail uses `policy.SMTP`
65
+ - iCloud's SMTP doesn't auto-save sent mail → owlpost APPENDs to Sent for you
66
+ - Gmail's SMTP *does* auto-save → owlpost skips the duplicate APPEND
67
+ - Folder names auto-discovered via RFC 6154 SPECIAL-USE (no hardcoding `Sent Messages` vs `[Gmail]/Sent Mail`)
68
+ - **Conversation following** — Gmail's `X-GM-THRID` extension where available, otherwise a generic Message-ID/References BFS across folders
69
+ - **Reliable connections** — short-lived per-operation IMAP sessions instead of long-lived ones that drop randomly
70
+ - **MIME-aware** — parses multipart messages, decodes headers, lists attachments, downloads them to disk
71
+ - **Threaded reply/forward** — preserves `In-Reply-To`/`References`, quotes the original
72
+
73
+ ## Tools
74
+
75
+ | Tool | What it does |
76
+ | --- | --- |
77
+ | `list_accounts` | List configured mail accounts |
78
+ | `list_folders` | List folders for an account, with detected special-use roles |
79
+ | `resolve_folder` | Resolve a role (`sent`, `trash`, `drafts`, `inbox`, `all`, `archive`) to a folder name |
80
+ | `search_messages` | Structured IMAP search (from/to/cc/subject/body/since/before/unseen/flagged/has_attachment), newest first |
81
+ | `read_email` | Read one message: headers, plaintext/HTML body, attachment list. Truncates by default to fit MCP result limits |
82
+ | `save_attachment` | Download an attachment to disk by part index |
83
+ | `get_conversation` | Return all messages in the same thread (Gmail X-GM-THRID or generic reference walking) |
84
+ | `send_email` | Send mail. Auto-saves to Sent on providers that don't (e.g. iCloud). Supports attachments, threading headers |
85
+ | `reply_email` | Reply (with optional reply-all), preserving threading and quoting |
86
+ | `forward_email` | Forward, re-attaching original attachments by default |
87
+ | `mark_read` | Set/unset `\Seen` |
88
+ | `flag_message` | Set/unset `\Flagged` (star) |
89
+ | `move_email` | Move to another folder |
90
+ | `delete_email` | Move to Trash |
91
+
92
+ ## Install
93
+
94
+ ```bash
95
+ pip install owlpost
96
+ # or with uv:
97
+ uv tool install owlpost
98
+ ```
99
+
100
+ ## Configure
101
+
102
+ Copy [`accounts.example.toml`](accounts.example.toml) to
103
+ `~/.config/owlpost/accounts.toml` and fill in your credentials. **Use
104
+ app-specific passwords**, not your real password:
105
+
106
+ - **iCloud**: [account.apple.com → Sign-In and Security → App-Specific Passwords](https://account.apple.com)
107
+ - **Gmail**: [myaccount.google.com/apppasswords](https://myaccount.google.com/apppasswords) (2FA must be enabled)
108
+
109
+ ```toml
110
+ [accounts.icloud]
111
+ email = "you@icloud.com"
112
+ password = "xxxx-xxxx-xxxx-xxxx"
113
+ provider = "icloud"
114
+ imap_host = "imap.mail.me.com"
115
+ imap_port = 993
116
+ smtp_host = "smtp.mail.me.com"
117
+ smtp_port = 587
118
+ auto_save_sent = true # iCloud SMTP doesn't auto-save sent
119
+
120
+ [accounts.gmail]
121
+ email = "you@gmail.com"
122
+ password = "xxxx xxxx xxxx xxxx"
123
+ provider = "gmail"
124
+ imap_host = "imap.gmail.com"
125
+ imap_port = 993
126
+ smtp_host = "smtp.gmail.com"
127
+ smtp_port = 587
128
+ auto_save_sent = false # Gmail SMTP auto-saves
129
+ ```
130
+
131
+ You can override the config path with the `OWLPOST_CONFIG` environment
132
+ variable.
133
+
134
+ ## Use with Claude Code
135
+
136
+ Add to `~/.claude.json` under `mcpServers`:
137
+
138
+ ```json
139
+ {
140
+ "mcpServers": {
141
+ "owlpost": {
142
+ "type": "stdio",
143
+ "command": "owlpost",
144
+ "args": [],
145
+ "env": {}
146
+ }
147
+ }
148
+ }
149
+ ```
150
+
151
+ Or, if you installed with `uv tool install`, the binary will be at
152
+ `~/.local/bin/owlpost`.
153
+
154
+ Restart Claude Code and the tools will appear under the `owlpost` namespace.
155
+
156
+ ## Use with Claude Desktop
157
+
158
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
159
+
160
+ ```json
161
+ {
162
+ "mcpServers": {
163
+ "owlpost": {
164
+ "command": "owlpost"
165
+ }
166
+ }
167
+ }
168
+ ```
169
+
170
+ ## Use with other MCP clients
171
+
172
+ owlpost speaks the standard MCP stdio transport — any MCP-compatible client
173
+ can talk to it by spawning the `owlpost` binary.
174
+
175
+ ## Examples
176
+
177
+ Once registered, you can ask Claude things like:
178
+
179
+ - *"Find emails from priya about the kids' school in the last month"*
180
+ - *"Show me the full thread for the latest mortgage email"*
181
+ - *"Reply to the most recent message from the landlord saying I'll be in touch tomorrow"*
182
+ - *"Forward the Manulife policy PDFs to Mom and Dad with Priyanka in CC"*
183
+ - *"Save the attachment from the Toronto Hydro bill to ~/Downloads"*
184
+
185
+ ## Provider notes
186
+
187
+ ### iCloud
188
+
189
+ - Use an [app-specific password](https://account.apple.com), not your Apple ID password.
190
+ - iCloud throttles aggressive reconnection. owlpost uses short-lived per-op sessions but doesn't pool — if you get `SSLEOFError: EOF`, back off for ~30 seconds.
191
+ - Sent folder is `Sent Messages`, Trash is `Deleted Messages`. Both are auto-detected.
192
+
193
+ ### Gmail
194
+
195
+ - Requires [2FA](https://myaccount.google.com/security) and an [app password](https://myaccount.google.com/apppasswords).
196
+ - IMAP must be enabled in [Gmail settings → Forwarding and POP/IMAP](https://mail.google.com/mail/u/0/#settings/fwdandpop).
197
+ - owlpost uses Gmail's `X-GM-THRID` extension for reliable thread detection.
198
+
199
+ ### Other providers
200
+
201
+ Set `provider = "generic"` and configure `imap_host`, `smtp_host`, ports, and
202
+ `smtp_security` (`starttls` for 587 or `ssl` for 465). Folder roles will
203
+ still be auto-detected if your provider supports SPECIAL-USE (most modern
204
+ ones do).
205
+
206
+ ## Development
207
+
208
+ ```bash
209
+ git clone https://github.com/smankoo/owlpost
210
+ cd owlpost
211
+ uv venv
212
+ uv pip install -e .
213
+ ```
214
+
215
+ Run the server directly to verify it starts:
216
+
217
+ ```bash
218
+ .venv/bin/owlpost
219
+ # (waits for MCP stdio input)
220
+ ```
221
+
222
+ ## License
223
+
224
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,176 @@
1
+ # owlpost
2
+
3
+ A high-fidelity IMAP/SMTP MCP server for iCloud, Gmail, and other mail
4
+ providers. Built because every other email MCP server I tried got tripped up
5
+ by real-world IMAP quirks (CRLF line endings, `RFC822` vs `BODY.PEEK[]`,
6
+ provider-specific Sent folders, multi-word search values).
7
+
8
+ owlpost is the one I actually use day-to-day from Claude Code to read,
9
+ search, follow conversations, and send mail.
10
+
11
+ ## Features
12
+
13
+ - **Multi-account** — configure as many mailboxes as you want, switch by name
14
+ - **iCloud and Gmail tested end-to-end**, with provider-specific quirks handled:
15
+ - iCloud's `RFC822` fetch returns empty bodies → uses `BODY.PEEK[]`
16
+ - iCloud's IMAP `APPEND` requires CRLF line endings → all outbound mail uses `policy.SMTP`
17
+ - iCloud's SMTP doesn't auto-save sent mail → owlpost APPENDs to Sent for you
18
+ - Gmail's SMTP *does* auto-save → owlpost skips the duplicate APPEND
19
+ - Folder names auto-discovered via RFC 6154 SPECIAL-USE (no hardcoding `Sent Messages` vs `[Gmail]/Sent Mail`)
20
+ - **Conversation following** — Gmail's `X-GM-THRID` extension where available, otherwise a generic Message-ID/References BFS across folders
21
+ - **Reliable connections** — short-lived per-operation IMAP sessions instead of long-lived ones that drop randomly
22
+ - **MIME-aware** — parses multipart messages, decodes headers, lists attachments, downloads them to disk
23
+ - **Threaded reply/forward** — preserves `In-Reply-To`/`References`, quotes the original
24
+
25
+ ## Tools
26
+
27
+ | Tool | What it does |
28
+ | --- | --- |
29
+ | `list_accounts` | List configured mail accounts |
30
+ | `list_folders` | List folders for an account, with detected special-use roles |
31
+ | `resolve_folder` | Resolve a role (`sent`, `trash`, `drafts`, `inbox`, `all`, `archive`) to a folder name |
32
+ | `search_messages` | Structured IMAP search (from/to/cc/subject/body/since/before/unseen/flagged/has_attachment), newest first |
33
+ | `read_email` | Read one message: headers, plaintext/HTML body, attachment list. Truncates by default to fit MCP result limits |
34
+ | `save_attachment` | Download an attachment to disk by part index |
35
+ | `get_conversation` | Return all messages in the same thread (Gmail X-GM-THRID or generic reference walking) |
36
+ | `send_email` | Send mail. Auto-saves to Sent on providers that don't (e.g. iCloud). Supports attachments, threading headers |
37
+ | `reply_email` | Reply (with optional reply-all), preserving threading and quoting |
38
+ | `forward_email` | Forward, re-attaching original attachments by default |
39
+ | `mark_read` | Set/unset `\Seen` |
40
+ | `flag_message` | Set/unset `\Flagged` (star) |
41
+ | `move_email` | Move to another folder |
42
+ | `delete_email` | Move to Trash |
43
+
44
+ ## Install
45
+
46
+ ```bash
47
+ pip install owlpost
48
+ # or with uv:
49
+ uv tool install owlpost
50
+ ```
51
+
52
+ ## Configure
53
+
54
+ Copy [`accounts.example.toml`](accounts.example.toml) to
55
+ `~/.config/owlpost/accounts.toml` and fill in your credentials. **Use
56
+ app-specific passwords**, not your real password:
57
+
58
+ - **iCloud**: [account.apple.com → Sign-In and Security → App-Specific Passwords](https://account.apple.com)
59
+ - **Gmail**: [myaccount.google.com/apppasswords](https://myaccount.google.com/apppasswords) (2FA must be enabled)
60
+
61
+ ```toml
62
+ [accounts.icloud]
63
+ email = "you@icloud.com"
64
+ password = "xxxx-xxxx-xxxx-xxxx"
65
+ provider = "icloud"
66
+ imap_host = "imap.mail.me.com"
67
+ imap_port = 993
68
+ smtp_host = "smtp.mail.me.com"
69
+ smtp_port = 587
70
+ auto_save_sent = true # iCloud SMTP doesn't auto-save sent
71
+
72
+ [accounts.gmail]
73
+ email = "you@gmail.com"
74
+ password = "xxxx xxxx xxxx xxxx"
75
+ provider = "gmail"
76
+ imap_host = "imap.gmail.com"
77
+ imap_port = 993
78
+ smtp_host = "smtp.gmail.com"
79
+ smtp_port = 587
80
+ auto_save_sent = false # Gmail SMTP auto-saves
81
+ ```
82
+
83
+ You can override the config path with the `OWLPOST_CONFIG` environment
84
+ variable.
85
+
86
+ ## Use with Claude Code
87
+
88
+ Add to `~/.claude.json` under `mcpServers`:
89
+
90
+ ```json
91
+ {
92
+ "mcpServers": {
93
+ "owlpost": {
94
+ "type": "stdio",
95
+ "command": "owlpost",
96
+ "args": [],
97
+ "env": {}
98
+ }
99
+ }
100
+ }
101
+ ```
102
+
103
+ Or, if you installed with `uv tool install`, the binary will be at
104
+ `~/.local/bin/owlpost`.
105
+
106
+ Restart Claude Code and the tools will appear under the `owlpost` namespace.
107
+
108
+ ## Use with Claude Desktop
109
+
110
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
111
+
112
+ ```json
113
+ {
114
+ "mcpServers": {
115
+ "owlpost": {
116
+ "command": "owlpost"
117
+ }
118
+ }
119
+ }
120
+ ```
121
+
122
+ ## Use with other MCP clients
123
+
124
+ owlpost speaks the standard MCP stdio transport — any MCP-compatible client
125
+ can talk to it by spawning the `owlpost` binary.
126
+
127
+ ## Examples
128
+
129
+ Once registered, you can ask Claude things like:
130
+
131
+ - *"Find emails from priya about the kids' school in the last month"*
132
+ - *"Show me the full thread for the latest mortgage email"*
133
+ - *"Reply to the most recent message from the landlord saying I'll be in touch tomorrow"*
134
+ - *"Forward the Manulife policy PDFs to Mom and Dad with Priyanka in CC"*
135
+ - *"Save the attachment from the Toronto Hydro bill to ~/Downloads"*
136
+
137
+ ## Provider notes
138
+
139
+ ### iCloud
140
+
141
+ - Use an [app-specific password](https://account.apple.com), not your Apple ID password.
142
+ - iCloud throttles aggressive reconnection. owlpost uses short-lived per-op sessions but doesn't pool — if you get `SSLEOFError: EOF`, back off for ~30 seconds.
143
+ - Sent folder is `Sent Messages`, Trash is `Deleted Messages`. Both are auto-detected.
144
+
145
+ ### Gmail
146
+
147
+ - Requires [2FA](https://myaccount.google.com/security) and an [app password](https://myaccount.google.com/apppasswords).
148
+ - IMAP must be enabled in [Gmail settings → Forwarding and POP/IMAP](https://mail.google.com/mail/u/0/#settings/fwdandpop).
149
+ - owlpost uses Gmail's `X-GM-THRID` extension for reliable thread detection.
150
+
151
+ ### Other providers
152
+
153
+ Set `provider = "generic"` and configure `imap_host`, `smtp_host`, ports, and
154
+ `smtp_security` (`starttls` for 587 or `ssl` for 465). Folder roles will
155
+ still be auto-detected if your provider supports SPECIAL-USE (most modern
156
+ ones do).
157
+
158
+ ## Development
159
+
160
+ ```bash
161
+ git clone https://github.com/smankoo/owlpost
162
+ cd owlpost
163
+ uv venv
164
+ uv pip install -e .
165
+ ```
166
+
167
+ Run the server directly to verify it starts:
168
+
169
+ ```bash
170
+ .venv/bin/owlpost
171
+ # (waits for MCP stdio input)
172
+ ```
173
+
174
+ ## License
175
+
176
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,46 @@
1
+ # owlpost account configuration — example
2
+ #
3
+ # Copy this file to ~/.config/owlpost/accounts.toml and fill in your own
4
+ # credentials. Each [accounts.<name>] block defines one mailbox. The <name>
5
+ # is what you'll pass to MCP tools as the `account` argument.
6
+ #
7
+ # IMPORTANT: use app-specific passwords, not your real password.
8
+ # - iCloud: https://account.apple.com → Sign-In and Security → App-Specific Passwords
9
+ # - Gmail: https://myaccount.google.com/apppasswords (requires 2FA enabled)
10
+
11
+ [accounts.icloud]
12
+ email = "you@icloud.com" # or your @me.com / custom domain alias
13
+ password = "xxxx-xxxx-xxxx-xxxx" # iCloud app-specific password
14
+ provider = "icloud"
15
+ imap_host = "imap.mail.me.com"
16
+ imap_port = 993
17
+ smtp_host = "smtp.mail.me.com"
18
+ smtp_port = 587
19
+ # iCloud SMTP does NOT auto-save sent messages — owlpost will APPEND to Sent.
20
+ auto_save_sent = true
21
+
22
+ [accounts.gmail]
23
+ email = "you@gmail.com"
24
+ password = "xxxx xxxx xxxx xxxx" # Gmail app password (16 chars, spaces ok)
25
+ provider = "gmail"
26
+ imap_host = "imap.gmail.com"
27
+ imap_port = 993
28
+ smtp_host = "smtp.gmail.com"
29
+ smtp_port = 587
30
+ # Gmail SMTP auto-saves to "Sent Mail" — APPENDing would create duplicates.
31
+ auto_save_sent = false
32
+
33
+ # Generic example for any other IMAP/SMTP provider (Fastmail, ProtonMail
34
+ # Bridge, your own server, etc.). Set provider = "generic" to skip
35
+ # provider-specific behaviors.
36
+ #
37
+ # [accounts.work]
38
+ # email = "you@example.com"
39
+ # password = "..."
40
+ # provider = "generic"
41
+ # imap_host = "imap.example.com"
42
+ # imap_port = 993
43
+ # smtp_host = "smtp.example.com"
44
+ # smtp_port = 587
45
+ # smtp_security = "starttls" # or "ssl" for port 465
46
+ # auto_save_sent = true
@@ -0,0 +1,61 @@
1
+ [project]
2
+ name = "owlpost"
3
+ version = "0.1.0"
4
+ description = "High-fidelity IMAP/SMTP MCP server for iCloud, Gmail, and other mail providers"
5
+ readme = "README.md"
6
+ license = { file = "LICENSE" }
7
+ requires-python = ">=3.11"
8
+ authors = [
9
+ { name = "Sumeet Singh Mankoo", email = "sumeet@mankoo.ca" },
10
+ ]
11
+ keywords = [
12
+ "mcp",
13
+ "model-context-protocol",
14
+ "imap",
15
+ "smtp",
16
+ "email",
17
+ "icloud",
18
+ "gmail",
19
+ "claude",
20
+ ]
21
+ classifiers = [
22
+ "Development Status :: 4 - Beta",
23
+ "Environment :: Console",
24
+ "Intended Audience :: Developers",
25
+ "Intended Audience :: End Users/Desktop",
26
+ "License :: OSI Approved :: MIT License",
27
+ "Operating System :: OS Independent",
28
+ "Programming Language :: Python :: 3",
29
+ "Programming Language :: Python :: 3.11",
30
+ "Programming Language :: Python :: 3.12",
31
+ "Programming Language :: Python :: 3.13",
32
+ "Topic :: Communications :: Email",
33
+ "Topic :: Communications :: Email :: Post-Office :: IMAP",
34
+ "Topic :: Software Development :: Libraries :: Python Modules",
35
+ ]
36
+ dependencies = [
37
+ "mcp>=1.2.0",
38
+ ]
39
+
40
+ [project.urls]
41
+ Homepage = "https://github.com/smankoo/owlpost"
42
+ Repository = "https://github.com/smankoo/owlpost"
43
+ Issues = "https://github.com/smankoo/owlpost/issues"
44
+
45
+ [project.scripts]
46
+ owlpost = "owlpost.server:main"
47
+
48
+ [build-system]
49
+ requires = ["hatchling"]
50
+ build-backend = "hatchling.build"
51
+
52
+ [tool.hatch.build.targets.wheel]
53
+ packages = ["src/owlpost"]
54
+
55
+ [tool.hatch.build.targets.sdist]
56
+ include = [
57
+ "src/owlpost",
58
+ "README.md",
59
+ "LICENSE",
60
+ "accounts.example.toml",
61
+ ]
@@ -0,0 +1 @@
1
+ """owlpost — high-fidelity IMAP/SMTP MCP server."""
@@ -0,0 +1,63 @@
1
+ """IMAP / SMTP connection helpers and the Account wrapper."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import imaplib
6
+ import smtplib
7
+ import ssl
8
+ from contextlib import contextmanager
9
+ from typing import Iterator
10
+
11
+ from .config import AccountConfig
12
+
13
+ # IMAP literal limit bumped — APPEND of large messages with attachments needs this.
14
+ imaplib._MAXLINE = 10 * 1024 * 1024 # 10 MB
15
+
16
+
17
+ class Account:
18
+ """Wraps an AccountConfig with connection helpers.
19
+
20
+ Connections are short-lived and re-opened per operation. This is the most
21
+ reliable model for IMAP — long-lived idle connections drop randomly and
22
+ state (selected folder, FETCH cursor, etc.) is hard to recover.
23
+ """
24
+
25
+ def __init__(self, cfg: AccountConfig):
26
+ self.cfg = cfg
27
+
28
+ @property
29
+ def name(self) -> str:
30
+ return self.cfg.name
31
+
32
+ @contextmanager
33
+ def imap(self) -> Iterator[imaplib.IMAP4_SSL]:
34
+ conn = imaplib.IMAP4_SSL(self.cfg.imap_host, self.cfg.imap_port)
35
+ try:
36
+ conn.login(self.cfg.email, self.cfg.password)
37
+ yield conn
38
+ finally:
39
+ try:
40
+ conn.logout()
41
+ except Exception:
42
+ pass
43
+
44
+ @contextmanager
45
+ def smtp(self) -> Iterator[smtplib.SMTP]:
46
+ ctx = ssl.create_default_context()
47
+ if self.cfg.smtp_security == "ssl":
48
+ conn = smtplib.SMTP_SSL(
49
+ self.cfg.smtp_host, self.cfg.smtp_port, context=ctx
50
+ )
51
+ else:
52
+ conn = smtplib.SMTP(self.cfg.smtp_host, self.cfg.smtp_port)
53
+ conn.ehlo()
54
+ conn.starttls(context=ctx)
55
+ conn.ehlo()
56
+ try:
57
+ conn.login(self.cfg.email, self.cfg.password)
58
+ yield conn
59
+ finally:
60
+ try:
61
+ conn.quit()
62
+ except Exception:
63
+ pass