Skip to main content

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.

Python 3.11+ License: MIT CI


๐Ÿคฏ 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, and rules --add works without one
  • 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.
  • 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.
  • Revoking access: Go to myaccount.google.com/permissions and remove mailtrim. Delete ~/.mailtrim/token.json locally 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.

  1. Go to console.cloud.google.com โ†’ New project
  2. APIs & Services โ†’ Enable APIs โ†’ search Gmail API โ†’ Enable
  3. OAuth consent screen โ†’ External โ†’ add your Gmail as a test user
  4. Credentials โ†’ Create โ†’ OAuth 2.0 Client ID โ†’ Desktop app โ†’ Download JSON
  5. Save it: mv ~/Downloads/client_secret_*.json ~/.mailtrim/credentials.json

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.

"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

mailtrim-0.1.0.tar.gz (73.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mailtrim-0.1.0-py3-none-any.whl (61.7 kB view details)

Uploaded Python 3

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

Hashes for mailtrim-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b6d3e896fe511c437e9b6cbed06da6006a4f3b167088c3b6e2f4cbeb3de6c171
MD5 87a5f882de5459d9a425b732b8b3330e
BLAKE2b-256 ab2546d7a689e41555ebac7f01bdbd8b6b23c0d3def7061923805cff6eebe562

See more details on using hashes here.

Provenance

The following attestation bundles were made for mailtrim-0.1.0.tar.gz:

Publisher: publish.yml on sadhgurutech/mailtrim

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for mailtrim-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 38850d430aebb81193250e41acdf46b71c7da132243b1956321b28b1b2d9f670
MD5 78d42ce3d3ec6e65776e702396ced17b
BLAKE2b-256 036fe44ce5db03368aa900c77356541b860c456e72782a4e59085d95d5c85bec

See more details on using hashes here.

Provenance

The following attestation bundles were made for mailtrim-0.1.0-py3-none-any.whl:

Publisher: publish.yml on sadhgurutech/mailtrim

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page