mail-digest
Skill7 starsChanged 9 months agoMITView on GitHub
Email digest for any time period — today, yesterday, last N hours/days, this week, a specific date, or while-I-was-away ranges. Categorizes by urgency, surfaces unread, flags financial/security emails, filters noise. Auto-invoke when user asks about email for any time period: "what came in today", "catch me up", "any emails this week", "what did I miss", "emails from yesterday", "last 3 hours", "since Monday".
In this repository32 other files it gives its agents.
- calendar-accountsSkill
- calendar-attendeesSkill
- calendar-conflictsSkill
- calendar-coreSkill
- calendar-eventSkill
- calendar-freeSkill
- calendar-recurringSkill
- calendar-searchSkill
- calendar-statsSkill
- calendar-todaySkill
- calendar-upcomingSkill
- mail-accountsSkill
- mail-action-itemsSkill
- mail-attachmentsSkill
- mail-bankingSkill
- mail-contactsSkill
- mail-coreSkill
- mail-expensesSkill
- mail-fromSkill
- mail-meetingsSkill
- mail-needs-replySkill
- mail-newsletterSkill
- mail-readSkill
- mail-searchSkill
- mail-securitySkill
- mail-statsSkill
- mail-subscriptionsSkill
- mail-threadSkill
- mail-top-sendersSkill
- mail-travelSkill
- mail-triageSkill
- mail-workSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 3 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 110
Always call out explicitly if found in the window:
- Distinctive: line 141
If the window has zero emails: say so and suggest a wider range.
- Distinctive: line 142
If the window has >200 emails: summarize by sender domain and ask if they want to drill into a category.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Mail Digest — Email Summary for Any Time Period
Period: $ARGUMENTS (default: today)
Step 1: Parse the time expression into a Unix timestamp range
Interpret $ARGUMENTS naturally. Map to START and END unix timestamps:
| Expression | START | END |
| "today" / (empty) | midnight today local | now |
| "yesterday" | midnight yesterday | midnight today |
| "last 2 hours" | now − 7200s | now |
| "last N hours" | now − N×3600s | now |
| "last N days" | now − N×86400s | now |
| "this week" | last Monday midnight | now |
| "last week" | Monday of prev week | last Sunday midnight |
| "since Monday" | most recent Monday midnight | now |
| "YYYY-MM-DD" | that date midnight | that date 23:59:59 |
| "catch me up" / "while I was away" | infer from context or ask — default last 5 days |
DB="$HOME/Library/Mail/V10/MailData/Envelope Index"
# Use SQLite date expressions directly — never compute Unix epochs manually (wrong year risk).
# "today" → >= date('now','localtime')
# "yesterday" → >= date('now','-1 day','localtime') AND < date('now','localtime')
# "last 48h" → >= datetime('now','-48 hours')
# "last 7 days" → >= date('now','-7 days','localtime')
# Apply the range in the WHERE clause below using datetime() comparisons.Step 2: Pull all messages in the window
sqlite3 "$DB" "
SELECT datetime(m.date_received,'unixepoch','localtime') as dt,
s.subject, a.address as sender, a.comment as name,
mb.url as mailbox, m.ROWID,
m.read, m.flagged, m.is_urgent, m.size,
m.automated_conversation, m.unsubscribe_type
FROM messages m
JOIN subjects s ON m.subject = s.ROWID
JOIN addresses a ON m.sender = a.ROWID
JOIN mailboxes mb ON m.mailbox = mb.ROWID
WHERE datetime(m.date_received,'unixepoch','localtime') >= date('now','localtime')
-- adjust the expression above based on $ARGUMENTS
AND m.deleted = 0
AND mb.url NOT LIKE '%Spam%'
AND mb.url NOT LIKE '%Trash%'
AND mb.url NOT LIKE '%Junk%'
AND mb.url NOT LIKE '%Draft%'
AND mb.url NOT LIKE '%Sent%'
ORDER BY m.is_urgent DESC, m.date_received DESC;" 2>/dev/nullStep 3: Categorize
Tier 1 — Needs Attention (read these):
is_urgent = 1flagged = 1read = 0ANDautomated_conversation != 2ANDunsubscribe_type = 0(real person, unread)- Subject contains: urgent, action required, ASAP, deadline, critical, review, approve, response needed
Tier 2 — FYI (skim):
automated_conversation = 1(transactional — Jira, Slack, bank receipts)- Reports, summaries, meeting notes, calendar invites
- Security alerts (login, 2FA, password) — even if automated
- Financial: receipts, payment confirmations, invoices
Tier 3 — Noise (count only, don't enumerate):
automated_conversation = 2— bulk automated emailsunsubscribe_type > 0— newsletter/mailing list emails- Monitoring subjects: PROBLEM:, OK:, ALARM:, CRIT:
- Break down by type: monitoring alerts, newsletters, marketing
For Tier 3, just report: "X automated emails (Y monitoring, Z CI/CD, W marketing)"
Step 4: Read bodies for Tier 1 items
For Tier 1 emails, get body preview. Check summaries table first (fast, no file I/O):
sqlite3 "$DB" "
SELECT m.ROWID, su.summary
FROM messages m
JOIN summaries su ON m.summary = su.ROWID
WHERE m.ROWID IN (<ROWID1>,<ROWID2>,...)" 2>/dev/nullFor any ROWIDs without a summary entry, fall back to emlx parsing:
python3 ~/.claude/skills/_mail-shared/parser.py <ROWID1> <ROWID2> ...Pull the first ~200 chars of meaningful body content as a preview for each.
Step 5: Surface special categories
Always call out explicitly if found in the window:
- Financial: subjects containing payment, receipt, invoice, transfer, transaction, billing → note count and total if parseable
- Security: login alerts, 2FA changes, password resets → flag every one
- Meetings: calendar invites or reschedules
- Unread from humans: these are the most likely to need action
Output Format
Email Digest — [RESOLVED DATE RANGE]
Total: X | Unread: Y | Flagged: Z | Accounts: N
Needs Attention (X)
| Time | From | Subject | Preview |
FYI (X)
| Time | From | Subject |
Financial (X emails)
- Brief list of transactions if detectable from subjects
Security (X events)
- Brief list
Noise filtered: X total (breakdown by type)
If the window has zero emails: say so and suggest a wider range. If the window has >200 emails: summarize by sender domain and ask if they want to drill into a category. Offer at the end: "Want me to read any of these, or dive into a specific category?"
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

