mailtrim 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.
mailtrim-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 mailtrim contributors
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.
@@ -0,0 +1,399 @@
1
+ Metadata-Version: 2.4
2
+ Name: mailtrim
3
+ Version: 0.1.0
4
+ Summary: Privacy-first Gmail inbox management β€” local-first core, optional AI via Anthropic API
5
+ Author: mailtrim contributors
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/sadhgurutech/mailtrim
8
+ Project-URL: Bug Tracker, https://github.com/sadhgurutech/mailtrim/issues
9
+ Project-URL: Source Code, https://github.com/sadhgurutech/mailtrim
10
+ Keywords: gmail,email,inbox,cleanup,productivity,cli,ai,anthropic,privacy
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: End Users/Desktop
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Communications :: Email
20
+ Classifier: Topic :: Utilities
21
+ Requires-Python: >=3.11
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: google-auth>=2.28.0
25
+ Requires-Dist: google-auth-oauthlib>=1.2.0
26
+ Requires-Dist: google-api-python-client>=2.120.0
27
+ Requires-Dist: anthropic>=0.40.0
28
+ Requires-Dist: typer>=0.12.0
29
+ Requires-Dist: rich>=13.7.0
30
+ Requires-Dist: sqlalchemy>=2.0.0
31
+ Requires-Dist: pydantic>=2.6.0
32
+ Requires-Dist: pydantic-settings>=2.2.0
33
+ Requires-Dist: httpx>=0.27.0
34
+ Requires-Dist: python-dateutil>=2.9.0
35
+ Requires-Dist: beautifulsoup4>=4.12.0
36
+ Requires-Dist: lxml>=5.1.0
37
+ Provides-Extra: headless
38
+ Requires-Dist: playwright>=1.44.0; extra == "headless"
39
+ Provides-Extra: dev
40
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
41
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
42
+ Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
43
+ Requires-Dist: ruff>=0.15.9; extra == "dev"
44
+ Requires-Dist: bandit>=1.7.0; extra == "dev"
45
+ Requires-Dist: pre-commit>=3.7.0; extra == "dev"
46
+ Dynamic: license-file
47
+
48
+ # mailtrim
49
+
50
+ **Delete years of Gmail clutter in minutes. Free, open-source. Core features need no API key.**
51
+
52
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://python.org)
53
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
54
+ [![CI](https://github.com/sadhgurutech/mailtrim/actions/workflows/ci.yml/badge.svg)](https://github.com/sadhgurutech/mailtrim/actions/workflows/ci.yml)
55
+
56
+ ---
57
+
58
+ > 🀯 495 emails deleted · 87.4 MB freed in 8s using mailtrim
59
+ > πŸ’₯ 34% of your inbox is clutter β€” caused by just 3 senders.
60
+
61
+ mailtrim is a CLI tool that finds inbox clutter, ranks it by impact, and bulk-deletes it safely β€” with a 30-day undo window.
62
+
63
+ **Core workflow (`stats`, `purge`, `undo`) is fully local** β€” no API key required, nothing sent anywhere. Optional AI commands (`triage`, `bulk`, `avoid`, `digest`, `rules --add`) send only email subjects and 300-character snippets to Anthropic for classification β€” never full body content. See [Anthropic's privacy policy](https://www.anthropic.com/privacy) for how API data is handled on their side.
64
+
65
+ No subscription. No black box.
66
+
67
+ ---
68
+
69
+ ## Why not SaneBox / Superhuman?
70
+
71
+ The paid tools charge $7–$40/month, process your email on their servers, and still don't solve the problems that matter most:
72
+
73
+ | Problem | SaneBox / Superhuman | mailtrim |
74
+ |---------|----------------------|------------|
75
+ | "Remind me only if they haven't replied" | βœ— Not solved | βœ… Conditional follow-up |
76
+ | *Why* did AI move this email? | βœ— Black box | βœ… One-line explanation per email |
77
+ | Natural language bulk cleanup | βœ— Not solved | βœ… "Archive newsletters older than 60 days" |
78
+ | 30-day undo for bulk operations | βœ— Not solved | βœ… Full undo log |
79
+ | "Emails I keep avoiding" detection | βœ— Not solved | βœ… AI insight per avoided email |
80
+ | Unsubscribe success rate | 70–85% | βœ… Near-100% (headless browser fallback) |
81
+ | Privacy β€” core commands local | βœ— Cloud-processed | βœ… Core: local only. AI commands: subjects/snippets to Anthropic |
82
+ | Cost | $7–$40/month | **Free** |
83
+
84
+ ---
85
+
86
+ ## Privacy
87
+
88
+ - **All data stays in `~/.mailtrim/`** β€” no external servers, no telemetry, no analytics
89
+ - **OAuth token** is written `chmod 0o600` (owner read-only)
90
+ - **AI features** send only email subjects and snippets to Anthropic β€” never full body content. See [Anthropic's privacy policy](https://www.anthropic.com/privacy) for their data handling.
91
+ - **No AI key?** β€” everything except `triage`, `bulk`, `avoid`, `digest`, and `rules --add` works without one
92
+ - **Why `gmail.modify` scope?** This grants read, compose, trash, and label access β€” mailtrim uses it to list messages, move mail to Trash, and manage labels. The scope technically permits reading full body content; mailtrim fetches metadata only and never reads or stores body text.
93
+ - **Why `gmail.send` scope?** The `follow-up` command creates reminder drafts. It is never called by `stats`, `purge`, `triage`, `bulk`, `undo`, or any cleanup command. If you don't use `follow-up`, this permission is never exercised.
94
+ - **Revoking access:** Go to [myaccount.google.com/permissions](https://myaccount.google.com/permissions) and remove mailtrim. Delete `~/.mailtrim/token.json` locally to complete the removal.
95
+ - See [PRIVACY.md](PRIVACY.md) for the full data flow
96
+
97
+ ---
98
+
99
+ ## What's free vs. paid?
100
+
101
+ | Feature | Commands | Cost |
102
+ |---------|----------|------|
103
+ | Inbox analysis + bulk delete | `stats`, `purge`, `undo`, `sync`, `unsubscribe`, `follow-up`, `rules --run` | **Free β€” no API key needed** |
104
+ | AI classification + NL cleanup | `triage`, `bulk`, `avoid`, `digest`, `rules --add` | Requires [Anthropic API key](https://console.anthropic.com) Β· ~$0.01–0.05 per run |
105
+
106
+ The core cleanup workflow β€” scan, rank, delete, undo β€” costs nothing and requires no AI key. AI features are optional and pay-per-use; there is no subscription.
107
+
108
+ ---
109
+
110
+ ## Quick start (~20 minutes first time, ~30 seconds after)
111
+
112
+ ### 1. Install
113
+
114
+ ```bash
115
+ git clone https://github.com/sadhgurutech/mailtrim
116
+ cd mailtrim
117
+ python3 -m venv venv && source venv/bin/activate
118
+ pip install -e .
119
+
120
+ # Optional: headless browser for near-100% unsubscribe success
121
+ pip install -e ".[headless]" && playwright install chromium
122
+ ```
123
+
124
+ ### 2. Get Gmail API credentials (one-time setup, ~15 minutes)
125
+
126
+ This is a standard OAuth setup β€” you're authorising yourself to access your own inbox. Google never charges for this. You only do this once; after that, `mailtrim auth` refreshes your token automatically.
127
+
128
+ > **Stuck?** The OAuth consent screen step trips up most people. When asked for "User type", choose **External**. Under "Test users", add your own Gmail address. That's it β€” you don't need to publish the app.
129
+
130
+ 1. Go to [console.cloud.google.com](https://console.cloud.google.com) β†’ **New project**
131
+ 2. **APIs & Services** β†’ **Enable APIs** β†’ search **Gmail API** β†’ Enable
132
+ 3. **OAuth consent screen** β†’ External β†’ add your Gmail as a **test user**
133
+ 4. **Credentials** β†’ Create β†’ **OAuth 2.0 Client ID** β†’ Desktop app β†’ Download JSON
134
+ 5. Save it: `mv ~/Downloads/client_secret_*.json ~/.mailtrim/credentials.json`
135
+
136
+ > **Scopes requested:** `gmail.modify` (read, trash, label management) and `gmail.send` (follow-up drafts). `gmail.modify` grants the capability to read body content β€” mailtrim never does, but you should know the scope allows it.
137
+
138
+ > **"This app isn't verified" warning:** Google shows this for any OAuth app that hasn't gone through their review process. It is expected and safe to proceed β€” you are authorising your own app to access your own inbox. Click **Advanced β†’ Go to mailtrim (unsafe)** to continue.
139
+
140
+ ### 3. Authenticate
141
+
142
+ ```bash
143
+ mailtrim auth
144
+ # Opens browser β†’ click Allow β†’ done
145
+ ```
146
+
147
+ ### 4. See what's in your inbox
148
+
149
+ ```bash
150
+ mailtrim stats
151
+ ```
152
+
153
+ **Sample output** *(illustrative β€” your numbers will vary)*:
154
+ ```
155
+ Scan complete β€” 2,000 emails Β· 38 senders
156
+
157
+ 34% of your inbox is clutter β€” caused by just 3 senders. 87.4 MB gone in one command.
158
+
159
+ TOTAL RECLAIMABLE SPACE
160
+ You can safely free ~87.4 MB (34.0% of scanned inbox)
161
+ from your top 3 senders Β· Each cleanup takes ~3-5s
162
+ All deletions go to Trash β€” undo anytime
163
+
164
+ # Impact Sender Emails Size Oldest Risk
165
+ 1 100 (High) LinkedIn Jobs 312 44.0MB 847d ago Safe to clean
166
+ 2 82 (High) Substack Weekly 183 26.1MB 512d ago Safe to clean
167
+ 3 51 (Medium) GitHub Notifications 147 9.3MB 91d ago Low risk
168
+ 4 29 (Low) Shopify 94 12.2MB 203d ago Safe to clean
169
+ 5 18 (Low) Medium Daily Digest 87 11.4MB 445d ago Safe to clean
170
+
171
+ Impact = 60% storage + 40% volume (0-100)
172
+ ```
173
+
174
+ ### 5. Bulk delete the offenders
175
+
176
+ ```bash
177
+ mailtrim purge
178
+ ```
179
+
180
+ **Sample output** *(illustrative)*:
181
+ ```
182
+ Top Email Offenders (823 emails Β· 102.3 MB)
183
+ # β”‚ Sender β”‚ Emails β”‚ Size β”‚ Latest β”‚ Sample subject
184
+ ───┼─────────────────────────────┼────────┼───────┼─────────┼─────────────────────────────
185
+ 1 β”‚ LinkedIn Jobs <jobs@li...> β”‚ 312 β”‚ 44MB β”‚ Apr 03 β”‚ 12 new jobs matching your...
186
+ 2 β”‚ Substack <hello@subst...> β”‚ 183 β”‚ 26MB β”‚ Apr 01 β”‚ This week: AI is eating...
187
+ 3 β”‚ GitHub <noreply@github...> β”‚ 147 β”‚ 9MB β”‚ Apr 04 β”‚ [myrepo] New issue opened...
188
+
189
+ Select senders to delete.
190
+ Enter numbers (1,3), ranges (1-5), all, or q to quit.
191
+
192
+ Your selection: 1,2
193
+
194
+ Selected 2 senders β€” 495 emails (70 MB):
195
+ βœ• LinkedIn Jobs (312 emails)
196
+ βœ• Substack (183 emails)
197
+
198
+ Move 495 emails to Trash? (undo available for 30 days) [y/N]: y
199
+
200
+ βœ“ Moved 495 emails to Trash. Undo log ID: 1 (mailtrim undo 1)
201
+ ```
202
+
203
+ ### 6. Share what you cleaned
204
+
205
+ ```bash
206
+ mailtrim stats --share
207
+ ```
208
+
209
+ The command outputs the following text, ready to copy and paste:
210
+
211
+ ```
212
+ 🀯 495 emails deleted · 87.4 MB freed in 8s using mailtrim
213
+ β€’ 3 senders responsible
214
+ β€’ Core cleanup runs locally β€” no API key needed
215
+ β€’ My inbox was 34% clutter β€” now it's clean
216
+ β€’ ~41 min of reading time reclaimed
217
+
218
+ Free forever. β†’ https://github.com/sadhgurutech/mailtrim
219
+ ```
220
+
221
+ ---
222
+
223
+ ## All Commands
224
+
225
+ ### `stats` β€” Quick inbox overview *(no AI needed)*
226
+
227
+ ```bash
228
+ mailtrim stats
229
+ mailtrim stats --json # machine-readable output
230
+ ```
231
+
232
+ ### `purge` β€” Bulk delete by sender *(no AI needed)*
233
+
234
+ **How the Risk/Confidence score works:**
235
+
236
+ Three signals combine to estimate how safe bulk-deletion is (0–100):
237
+
238
+ | Signal | Weight | Logic |
239
+ |--------|--------|-------|
240
+ | `List-Unsubscribe` header present | 30 pts | Sender self-identifies as bulk/marketing |
241
+ | Age β‰₯ 180 days in inbox | up to 35 pts | Emails sitting >6 months are rarely actionable |
242
+ | Volume β‰₯ 50 from one sender | up to 35 pts | High frequency = almost certainly automated |
243
+
244
+ 🟒 β‰₯70 = Safe to clean Β· 🟑 40–69 = Low risk Β· πŸ”΄ <40 = Review first
245
+
246
+ Scores are heuristics β€” the 30-day undo exists precisely because no heuristic is perfect.
247
+
248
+ ```bash
249
+ mailtrim purge # sort by email count (default)
250
+ mailtrim purge --sort oldest # show oldest clutter first
251
+ mailtrim purge --sort size # largest senders first
252
+ mailtrim purge --query "older_than:1y" # custom query
253
+ mailtrim purge --unsub # also unsubscribe while deleting
254
+ mailtrim purge --permanent # skip Trash β€” IRREVERSIBLE
255
+ mailtrim purge --json # output sender list as JSON
256
+ ```
257
+
258
+ ### `sync` β€” Pull inbox into local cache
259
+
260
+ ```bash
261
+ mailtrim sync # last 200 messages
262
+ mailtrim sync --limit 500
263
+ mailtrim sync --query "in:inbox is:unread"
264
+ ```
265
+
266
+ ### `triage` β€” AI inbox classification
267
+
268
+ ```bash
269
+ mailtrim triage # classify unread inbox
270
+ mailtrim triage --limit 50
271
+ ```
272
+
273
+ Every email gets: **priority** (high/medium/low) Β· **category** Β· **why** Β· **suggested action**
274
+
275
+ ### `bulk` β€” Natural language bulk operations
276
+
277
+ ```bash
278
+ mailtrim bulk "archive all newsletters I haven't opened in 60 days"
279
+ mailtrim bulk "delete all emails from noreply@* older than 1 year"
280
+ mailtrim bulk "label receipts from order@ or receipt@ senders"
281
+ mailtrim bulk "archive LinkedIn notifications" --dry-run # preview first
282
+ ```
283
+
284
+ ### `undo` β€” Reverse a bulk operation (within 30 days)
285
+
286
+ ```bash
287
+ mailtrim undo # list recent operations
288
+ mailtrim undo 42 # undo operation #42
289
+ ```
290
+
291
+ ### `follow-up` β€” Conditional follow-up tracking
292
+
293
+ ```bash
294
+ mailtrim follow-up <message-id> --days 3 # remind only if no reply in 3 days
295
+ mailtrim follow-up --list # see what's due today
296
+ mailtrim follow-up --sync # check threads for replies
297
+ ```
298
+
299
+ ### `avoid` β€” Emails you keep putting off
300
+
301
+ ```bash
302
+ mailtrim avoid # show with AI insight
303
+ mailtrim avoid --no-insights # faster, no AI
304
+ mailtrim avoid --process <id> --action archive
305
+ ```
306
+
307
+ ### `unsubscribe` β€” Unsubscribe that actually works
308
+
309
+ ```bash
310
+ mailtrim unsubscribe newsletters@company.com
311
+ mailtrim unsubscribe --from-query "label:newsletters" --limit 20
312
+ mailtrim unsubscribe --history
313
+ ```
314
+
315
+ ### `rules` β€” Recurring automation
316
+
317
+ ```bash
318
+ mailtrim rules --add "archive LinkedIn notifications older than 7 days"
319
+ mailtrim rules --list
320
+ mailtrim rules --run
321
+ mailtrim rules --run --dry-run
322
+ ```
323
+
324
+ ### `digest` β€” Weekly inbox summary
325
+
326
+ ```bash
327
+ mailtrim digest
328
+ ```
329
+
330
+ ---
331
+
332
+ ## Configuration
333
+
334
+ All settings via environment variables or `~/.mailtrim/.env`:
335
+
336
+ | Variable | Default | Description |
337
+ |----------|---------|-------------|
338
+ | `ANTHROPIC_API_KEY` | *(not set)* | Anthropic API key. Without it, mock AI mode is used. |
339
+ | `MAILTRIM_AI_MODEL` | `claude-sonnet-4-6` | Claude model for AI features |
340
+ | `MAILTRIM_DRY_RUN` | `false` | Global dry-run (preview without executing) |
341
+ | `MAILTRIM_UNDO_WINDOW_DAYS` | `30` | How long undo logs are kept |
342
+ | `MAILTRIM_AVOIDANCE_VIEW_THRESHOLD` | `3` | Views before an email is "avoided" |
343
+ | `MAILTRIM_FOLLOW_UP_DEFAULT_DAYS` | `3` | Default follow-up window |
344
+ | `MAILTRIM_DIR` | `~/.mailtrim` | Where tokens, DB, and config are stored |
345
+
346
+ **`~/.mailtrim/.env` example:**
347
+ ```
348
+ ANTHROPIC_API_KEY=sk-ant-...
349
+ MAILTRIM_DRY_RUN=false
350
+ MAILTRIM_UNDO_WINDOW_DAYS=30
351
+ ```
352
+
353
+ > **Security note:** Restrict permissions on this file β€” `chmod 600 ~/.mailtrim/.env` β€” so only your user account can read the API key.
354
+
355
+ ---
356
+
357
+ ## Testing (no credentials required)
358
+
359
+ ```bash
360
+ # Run all 115 tests β€” zero API calls, zero credentials needed
361
+ python -m pytest tests/ -v
362
+
363
+ # With coverage
364
+ python -m pytest tests/ --cov=mailtrim --cov-report=term-missing
365
+ ```
366
+
367
+ All AI paths are covered by `MockAIEngine` β€” the full CLI can be exercised without any API key.
368
+
369
+ ---
370
+
371
+ ## Contributing
372
+
373
+ See [CONTRIBUTING.md](CONTRIBUTING.md). Bug reports and feature requests welcome via [GitHub Issues](../../issues).
374
+
375
+ ---
376
+
377
+ ## Architecture
378
+
379
+ ```
380
+ mailtrim/
381
+ β”œβ”€β”€ config.py # Settings (env vars, ~/.mailtrim/.env)
382
+ β”œβ”€β”€ core/
383
+ β”‚ β”œβ”€β”€ gmail_client.py # Gmail API: OAuth, CRUD, batching, retry on 429/5xx
384
+ β”‚ β”œβ”€β”€ storage.py # Local SQLite: emails, follow-ups, rules, undo log
385
+ β”‚ β”œβ”€β”€ ai_engine.py # Claude API: classify, NLβ†’query, digest, avoidance
386
+ β”‚ β”œβ”€β”€ mock_ai.py # Deterministic stub β€” full testing without API key
387
+ β”‚ β”œβ”€β”€ follow_up.py # Conditional follow-up: only surfaces if no reply
388
+ β”‚ β”œβ”€β”€ bulk_engine.py # NL β†’ dry-run preview β†’ execute β†’ 30-day undo
389
+ β”‚ β”œβ”€β”€ avoidance.py # "Emails you avoid" detector + per-email AI insight
390
+ β”‚ β”œβ”€β”€ unsubscribe.py # RFC 8058 one-click + mailto + Playwright headless
391
+ β”‚ └── sender_stats.py # Sender aggregation for stats/purge commands
392
+ └── cli/main.py # Typer + Rich CLI β€” 11 commands
393
+ ```
394
+
395
+ ---
396
+
397
+ ## License
398
+
399
+ [MIT](LICENSE) β€” free to use, modify, and distribute.