Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Gmail Digest

Triage several Gmail accounts into one Discord feed. Urgent mail reaches you in 30 minutes; marketing never does.

 3,000 unread across 3 accounts, none of it sorted
        ↓
   Gmail Digest
        ↓
 #digest    every 24h — an interview / academic / important summary
 #urgent    within 30min + @you — interviews, assessments, a professor's reply
 #ignored   marketing and receipts, there if you want them
 #bot       /search /mute /boost /push — slash commands with autocomplete

Why not just use Gmail filters

Filters match strings. They cannot tell "we'd like to schedule an interview" from "we'd like to tell you about our bootcamp", and they cannot notice that a recruiter replied in a thread you were waiting on.

This does three things filters cannot:

  • Classifies by intent, with an optional LLM pass that must quote the source line for any judgment it makes — so a wrong call is visible rather than mysterious.
  • Tracks what you are waiting for. Reply to a scheduling email and it opens a pending item; when the confirmation lands it closes it.
  • Escalates on a clock. A digest is fine for a newsletter and useless for an assessment that expires tonight, so urgent mail gets its own 30-minute path.

What's in it

  • Multiple Gmail accounts — work, school, personal, as many as you have
  • Local by default — OAuth tokens stay on your machine; readonly scope
  • Discord-native slash commands with autocomplete: /search /mute /boost /push /ask
  • Action checklist — anything needing a reply is surfaced first and never truncated
  • Optional LLM enhancement — bring your own key. Anthropic, OpenAI, OpenRouter, Groq, Together, or local Ollama. Every LLM judgment carries a quote from the email.
  • Ask questions in plain language — "did Acme reply yet", "what's tomorrow morning" — answered from your own mail with citations
  • WeCom (企业微信) push as an alternative to Discord
  • Rolling 24h schedule, adjustable, plus manual pull any time
  • 100 tests, run with pytest

Setup

git clone <this repo> && cd gmail_digest
pip install -r requirements.txt

# 1. Gmail OAuth — put your Google Cloud client_secret at
#    ~/.config/gmail_digest/credentials.json, then per account:
python digest.py auth you@gmail.com
python digest.py auth you@work.com

# 2. Try it without any Discord setup
python digest.py digest --dry-run

# 3. Wire up Discord (bot token + channel ids) and run the daemon
python bot_daemon.py

Scope requested is gmail.readonly. Cleanup features that trash mail ask for a separate, explicitly granted scope, and confirm before acting.


Make it yours

The classifier ships with generic rules. The things that are about you — your school, your bank, how you want the assistant to describe you — live in one optional file:

// ~/.config/gmail_digest/profile.json      (see profile.json.example)
{
  "description": "a job-searching CS grad student",   // goes into the LLM prompt
  "timezone": "America/New_York",
  "account_labels":     { "myuniversity.edu": "Uni" },  // compact tags in the feed
  "academic_domains":   ["myuniversity.edu"],           // counts as academic mail
  "important_senders":  ["registrar@myuniversity.edu"], // always surfaced
  "newsletter_senders": ["news@myuniversity.edu"]       // always demoted
}

Everything is optional and the defaults work without it. Nothing school-specific is compiled into the code.


Layout

module what it does
gmail_client.py OAuth, message fetch, normalised Message
classify.py rule-based categorisation — the deterministic first pass
llm.py optional LLM judgment, multi-provider, quote-required
digest.py digest assembly + CLI
discord_bot.py / discord_channel.py / bot_daemon.py Discord surface
reminders.py / state.py pending items, reminders, persistence
qa.py / nl_router.py plain-language questions over your own mail
wecom.py / wechat_*.py WeCom push
user_profile.py the per-user config above
cleanup.py opt-in bulk cleanup, always confirmed

Design notes

Rules first, model second. Most mail is decidable without an LLM, and rules are free, instant, and debuggable. The model only sees what the rules were unsure about — which keeps the bill near zero and means an outage degrades the product rather than breaking it.

Every LLM judgment must quote the email. The schema requires an evidence_quote. A model that cannot point at a line is not allowed to star a message. This is the difference between a classifier you can audit and one you have to trust.

Failures are visible. A message that could not be fetched or judged is reported as such rather than silently dropped — a triage tool that quietly loses mail is worse than no tool.


License

MIT.


中文安装指南

完整的分步安装说明(含 Google Cloud 项目、Discord bot、launchd 自启)见 SETUP_zh.md

About

Triage several Gmail accounts into one Discord feed. Rules-first classification with an optional LLM pass that must quote the email for every judgment it makes. Urgent mail escalates in 30 minutes; marketing never does.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages