Privacy-first Gmail inbox management โ local-first core, optional AI via Anthropic API
Project description
mailtrim
Delete years of Gmail clutter in minutes. Free, open-source. Core features need no API key.
๐คฏ 495 emails deleted ยท 87.4 MB freed in 8s using mailtrim ๐ฅ 34% of your inbox is clutter โ caused by just 3 senders.
mailtrim is a CLI tool that finds inbox clutter, ranks it by impact, and bulk-deletes it safely โ with a 30-day undo window.
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 for how API data is handled on their side.
No subscription. No black box.
Why not SaneBox / Superhuman?
The paid tools charge $7โ$40/month, process your email on their servers, and still don't solve the problems that matter most:
| Problem | SaneBox / Superhuman | mailtrim |
|---|---|---|
| "Remind me only if they haven't replied" | โ Not solved | โ Conditional follow-up |
| Why did AI move this email? | โ Black box | โ One-line explanation per email |
| Natural language bulk cleanup | โ Not solved | โ "Archive newsletters older than 60 days" |
| 30-day undo for bulk operations | โ Not solved | โ Full undo log |
| "Emails I keep avoiding" detection | โ Not solved | โ AI insight per avoided email |
| Unsubscribe success rate | 70โ85% | โ Near-100% (headless browser fallback) |
| Privacy โ core commands local | โ Cloud-processed | โ Core: local only. AI commands: subjects/snippets to Anthropic |
| Cost | $7โ$40/month | Free |
Privacy
- All data stays in
~/.mailtrim/โ no external servers, no telemetry, no analytics - OAuth token is written
chmod 0o600(owner read-only) - AI features send only email subjects and snippets to Anthropic โ never full body content. See Anthropic's privacy policy for their data handling.
- No AI key? โ everything except
triage,bulk,avoid,digest, andrules --addworks without one - Why
gmail.modifyscope? 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. - Why
gmail.sendscope? Thefollow-upcommand creates reminder drafts. It is never called bystats,purge,triage,bulk,undo, or any cleanup command. If you don't usefollow-up, this permission is never exercised. - Revoking access: Go to myaccount.google.com/permissions and remove mailtrim. Delete
~/.mailtrim/token.jsonlocally to complete the removal. - See PRIVACY.md for the full data flow
What's free vs. paid?
| Feature | Commands | Cost |
|---|---|---|
| Inbox analysis + bulk delete | stats, purge, undo, sync, unsubscribe, follow-up, rules --run |
Free โ no API key needed |
| AI classification + NL cleanup | triage, bulk, avoid, digest, rules --add |
Requires Anthropic API key ยท ~$0.01โ0.05 per run |
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.
Quick start (~20 minutes first time, ~30 seconds after)
1. Install
git clone https://github.com/sadhgurutech/mailtrim
cd mailtrim
python3 -m venv venv && source venv/bin/activate
pip install -e .
# Optional: headless browser for near-100% unsubscribe success
pip install -e ".[headless]" && playwright install chromium
2. Get Gmail API credentials (one-time setup, ~15 minutes)
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.
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.
- Go to console.cloud.google.com โ New project
- APIs & Services โ Enable APIs โ search Gmail API โ Enable
- OAuth consent screen โ External โ add your Gmail as a test user
- Credentials โ Create โ OAuth 2.0 Client ID โ Desktop app โ Download JSON
- Save it:
mv ~/Downloads/client_secret_*.json ~/.mailtrim/credentials.json
Scopes requested:
gmail.modify(read, trash, label management) andgmail.send(follow-up drafts).gmail.modifygrants the capability to read body content โ mailtrim never does, but you should know the scope allows it.
"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.
3. Authenticate
mailtrim auth
# Opens browser โ click Allow โ done
4. See what's in your inbox
mailtrim stats
Sample output (illustrative โ your numbers will vary):
Scan complete โ 2,000 emails ยท 38 senders
34% of your inbox is clutter โ caused by just 3 senders. 87.4 MB gone in one command.
TOTAL RECLAIMABLE SPACE
You can safely free ~87.4 MB (34.0% of scanned inbox)
from your top 3 senders ยท Each cleanup takes ~3-5s
All deletions go to Trash โ undo anytime
# Impact Sender Emails Size Oldest Risk
1 100 (High) LinkedIn Jobs 312 44.0MB 847d ago Safe to clean
2 82 (High) Substack Weekly 183 26.1MB 512d ago Safe to clean
3 51 (Medium) GitHub Notifications 147 9.3MB 91d ago Low risk
4 29 (Low) Shopify 94 12.2MB 203d ago Safe to clean
5 18 (Low) Medium Daily Digest 87 11.4MB 445d ago Safe to clean
Impact = 60% storage + 40% volume (0-100)
5. Bulk delete the offenders
mailtrim purge
Sample output (illustrative):
Top Email Offenders (823 emails ยท 102.3 MB)
# โ Sender โ Emails โ Size โ Latest โ Sample subject
โโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโผโโโโโโโโผโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
1 โ LinkedIn Jobs <jobs@li...> โ 312 โ 44MB โ Apr 03 โ 12 new jobs matching your...
2 โ Substack <hello@subst...> โ 183 โ 26MB โ Apr 01 โ This week: AI is eating...
3 โ GitHub <noreply@github...> โ 147 โ 9MB โ Apr 04 โ [myrepo] New issue opened...
Select senders to delete.
Enter numbers (1,3), ranges (1-5), all, or q to quit.
Your selection: 1,2
Selected 2 senders โ 495 emails (70 MB):
โ LinkedIn Jobs (312 emails)
โ Substack (183 emails)
Move 495 emails to Trash? (undo available for 30 days) [y/N]: y
โ Moved 495 emails to Trash. Undo log ID: 1 (mailtrim undo 1)
6. Share what you cleaned
mailtrim stats --share
The command outputs the following text, ready to copy and paste:
๐คฏ 495 emails deleted ยท 87.4 MB freed in 8s using mailtrim
โข 3 senders responsible
โข Core cleanup runs locally โ no API key needed
โข My inbox was 34% clutter โ now it's clean
โข ~41 min of reading time reclaimed
Free forever. โ https://github.com/sadhgurutech/mailtrim
All Commands
stats โ Quick inbox overview (no AI needed)
mailtrim stats
mailtrim stats --json # machine-readable output
purge โ Bulk delete by sender (no AI needed)
How the Risk/Confidence score works:
Three signals combine to estimate how safe bulk-deletion is (0โ100):
| Signal | Weight | Logic |
|---|---|---|
List-Unsubscribe header present |
30 pts | Sender self-identifies as bulk/marketing |
| Age โฅ 180 days in inbox | up to 35 pts | Emails sitting >6 months are rarely actionable |
| Volume โฅ 50 from one sender | up to 35 pts | High frequency = almost certainly automated |
๐ข โฅ70 = Safe to clean ยท ๐ก 40โ69 = Low risk ยท ๐ด <40 = Review first
Scores are heuristics โ the 30-day undo exists precisely because no heuristic is perfect.
mailtrim purge # sort by email count (default)
mailtrim purge --sort oldest # show oldest clutter first
mailtrim purge --sort size # largest senders first
mailtrim purge --query "older_than:1y" # custom query
mailtrim purge --unsub # also unsubscribe while deleting
mailtrim purge --permanent # skip Trash โ IRREVERSIBLE
mailtrim purge --json # output sender list as JSON
sync โ Pull inbox into local cache
mailtrim sync # last 200 messages
mailtrim sync --limit 500
mailtrim sync --query "in:inbox is:unread"
triage โ AI inbox classification
mailtrim triage # classify unread inbox
mailtrim triage --limit 50
Every email gets: priority (high/medium/low) ยท category ยท why ยท suggested action
bulk โ Natural language bulk operations
mailtrim bulk "archive all newsletters I haven't opened in 60 days"
mailtrim bulk "delete all emails from noreply@* older than 1 year"
mailtrim bulk "label receipts from order@ or receipt@ senders"
mailtrim bulk "archive LinkedIn notifications" --dry-run # preview first
undo โ Reverse a bulk operation (within 30 days)
mailtrim undo # list recent operations
mailtrim undo 42 # undo operation #42
follow-up โ Conditional follow-up tracking
mailtrim follow-up <message-id> --days 3 # remind only if no reply in 3 days
mailtrim follow-up --list # see what's due today
mailtrim follow-up --sync # check threads for replies
avoid โ Emails you keep putting off
mailtrim avoid # show with AI insight
mailtrim avoid --no-insights # faster, no AI
mailtrim avoid --process <id> --action archive
unsubscribe โ Unsubscribe that actually works
mailtrim unsubscribe newsletters@company.com
mailtrim unsubscribe --from-query "label:newsletters" --limit 20
mailtrim unsubscribe --history
rules โ Recurring automation
mailtrim rules --add "archive LinkedIn notifications older than 7 days"
mailtrim rules --list
mailtrim rules --run
mailtrim rules --run --dry-run
digest โ Weekly inbox summary
mailtrim digest
Configuration
All settings via environment variables or ~/.mailtrim/.env:
| Variable | Default | Description |
|---|---|---|
ANTHROPIC_API_KEY |
(not set) | Anthropic API key. Without it, mock AI mode is used. |
MAILTRIM_AI_MODEL |
claude-sonnet-4-6 |
Claude model for AI features |
MAILTRIM_DRY_RUN |
false |
Global dry-run (preview without executing) |
MAILTRIM_UNDO_WINDOW_DAYS |
30 |
How long undo logs are kept |
MAILTRIM_AVOIDANCE_VIEW_THRESHOLD |
3 |
Views before an email is "avoided" |
MAILTRIM_FOLLOW_UP_DEFAULT_DAYS |
3 |
Default follow-up window |
MAILTRIM_DIR |
~/.mailtrim |
Where tokens, DB, and config are stored |
~/.mailtrim/.env example:
ANTHROPIC_API_KEY=sk-ant-...
MAILTRIM_DRY_RUN=false
MAILTRIM_UNDO_WINDOW_DAYS=30
Security note: Restrict permissions on this file โ
chmod 600 ~/.mailtrim/.envโ so only your user account can read the API key.
Testing (no credentials required)
# Run all 115 tests โ zero API calls, zero credentials needed
python -m pytest tests/ -v
# With coverage
python -m pytest tests/ --cov=mailtrim --cov-report=term-missing
All AI paths are covered by MockAIEngine โ the full CLI can be exercised without any API key.
Contributing
See CONTRIBUTING.md. Bug reports and feature requests welcome via GitHub Issues.
Architecture
mailtrim/
โโโ config.py # Settings (env vars, ~/.mailtrim/.env)
โโโ core/
โ โโโ gmail_client.py # Gmail API: OAuth, CRUD, batching, retry on 429/5xx
โ โโโ storage.py # Local SQLite: emails, follow-ups, rules, undo log
โ โโโ ai_engine.py # Claude API: classify, NLโquery, digest, avoidance
โ โโโ mock_ai.py # Deterministic stub โ full testing without API key
โ โโโ follow_up.py # Conditional follow-up: only surfaces if no reply
โ โโโ bulk_engine.py # NL โ dry-run preview โ execute โ 30-day undo
โ โโโ avoidance.py # "Emails you avoid" detector + per-email AI insight
โ โโโ unsubscribe.py # RFC 8058 one-click + mailto + Playwright headless
โ โโโ sender_stats.py # Sender aggregation for stats/purge commands
โโโ cli/main.py # Typer + Rich CLI โ 11 commands
License
MIT โ free to use, modify, and distribute.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mailtrim-0.1.0.tar.gz.
File metadata
- Download URL: mailtrim-0.1.0.tar.gz
- Upload date:
- Size: 73.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6d3e896fe511c437e9b6cbed06da6006a4f3b167088c3b6e2f4cbeb3de6c171
|
|
| MD5 |
87a5f882de5459d9a425b732b8b3330e
|
|
| BLAKE2b-256 |
ab2546d7a689e41555ebac7f01bdbd8b6b23c0d3def7061923805cff6eebe562
|
Provenance
The following attestation bundles were made for mailtrim-0.1.0.tar.gz:
Publisher:
publish.yml on sadhgurutech/mailtrim
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mailtrim-0.1.0.tar.gz -
Subject digest:
b6d3e896fe511c437e9b6cbed06da6006a4f3b167088c3b6e2f4cbeb3de6c171 - Sigstore transparency entry: 1240373954
- Sigstore integration time:
-
Permalink:
sadhgurutech/mailtrim@9ad1c3b0ba053aa21d5ea5943bb7a7f7c026a14c -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/sadhgurutech
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9ad1c3b0ba053aa21d5ea5943bb7a7f7c026a14c -
Trigger Event:
push
-
Statement type:
File details
Details for the file mailtrim-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mailtrim-0.1.0-py3-none-any.whl
- Upload date:
- Size: 61.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
38850d430aebb81193250e41acdf46b71c7da132243b1956321b28b1b2d9f670
|
|
| MD5 |
78d42ce3d3ec6e65776e702396ced17b
|
|
| BLAKE2b-256 |
036fe44ce5db03368aa900c77356541b860c456e72782a4e59085d95d5c85bec
|
Provenance
The following attestation bundles were made for mailtrim-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on sadhgurutech/mailtrim
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mailtrim-0.1.0-py3-none-any.whl -
Subject digest:
38850d430aebb81193250e41acdf46b71c7da132243b1956321b28b1b2d9f670 - Sigstore transparency entry: 1240373987
- Sigstore integration time:
-
Permalink:
sadhgurutech/mailtrim@9ad1c3b0ba053aa21d5ea5943bb7a7f7c026a14c -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/sadhgurutech
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9ad1c3b0ba053aa21d5ea5943bb7a7f7c026a14c -
Trigger Event:
push
-
Statement type: