← SENTINEL-01
TX-002 · DECRYPTED
2026-03-16/4 MIN READ

Email Triage Automation: How I Never Miss a Message

Client emails, support requests, newsletters, invoices — everything gets triaged, categorized, and either handled automatically or surfaced to me with full context.

EMAILAUTOMATIONPRODUCTIVITY

When you run a company alone, email is where everything happens. Clients send change requests, approve deliverables, ask for quotes, and shift priorities, all through email. Miss one message from a client and you're scrambling to explain why the feature they asked for two weeks ago isn't even started.

I built a system that syncs, classifies, analyzes, and surfaces my email every morning with full context. It doesn't reply for me, because I'd never trust AI for client correspondence, but it does everything else.

The Sync Layer

A Python script called sync_mail.py runs every 30 minutes via a macOS LaunchAgent. It reads directly from Apple Mail using JXA (JavaScript for Automation) through osascript, with no IMAP parsing and no external libraries.

It reads the iCloud account, specifically the "subralabs" mailbox. Up to 50 messages per run, body truncated at 10,000 characters. It handles bidirectional sync, pulling both received emails and emails I've sent from [email protected]. The sent mail sync tries multiple mailbox names because of locale differences: "Sent Messages", "Sent", "Inviata", "Gesendet". If you've ever dealt with Apple Mail on a machine set to German or Italian, you know why.

Sent emails get saved with an inviata_ prefix in the filename. This becomes important later for figuring out which threads I've already replied to.

Classification and Threading

Every email gets sorted into project folders using keyword-based rules:

  • mail/arabia/ matches keywords like "arabia", "saudi", "atlas", "heritage", "testflight", "beta 3", plus the client's email address
  • mail/resorts/ matches "resorts", "magazine", "rivista"
  • mail/subralabs/ matches "subralabs", "subra labs", "sito", "cloudflare"
  • mail/generale/ is the fallback for everything else

A single email can land in multiple folders if it matches multiple rules. All email files are gitignored and never touch GitHub. Privacy is non-negotiable.

Threading uses a simple approach: a slugify() function takes the subject line, strips prefixes like "Re:", "Fwd:", "R:", "I:", normalizes the text, and produces a slug. That slug becomes part of the filename and the Thread field in the markdown file. All files with the same slug belong to the same thread. So "R: Versione Beta 3.3" and "Re: Versione Beta 3.3" both produce versione-beta-33.

Each email becomes a markdown file:

# Subject Line

**Data:** 2026-03-31
**Da:** [email protected]
**A:** [email protected]
**Progetto:** arabia
**Thread:** versione-beta-33

> Email body, quoted line by line

No RFC message-ID header parsing. It would be more "correct" but the complexity isn't worth it for my volume.

The COO Agent: Point-by-Point Triage

A Claude Code agent configured as COO (Chief Operating Officer) runs daily via Cowork, Anthropic's desktop app for scheduled autonomous tasks. This is the brain of the system.

It reads all emails from the last 3 days and matches received emails with sent ones on the same thread to determine if I've already replied. Then it does a point-by-point analysis of every client email. Each request, decision, priority change, financial mention, deadline, or preference gets extracted and annotated. Even subtext: if a client writes "limando un po' i costi" (trimming costs a bit), the agent interprets that as "the client wants a discount" and flags it.

Urgency classification works on three levels: high means a response is needed today, medium means within 2-3 days, and low is purely informational.

Client emails without a reply for more than 2 days get flagged as URGENT. The agent drafts responses in my writing style, formal with clients, signed "Cordiali saluti, Martino Vigiani, SubraLabs". It also creates tasks in the shared task system for pending actions.

How It Fits Into My Daily Workflow

The email triage plugs into the session lifecycle at multiple points.

The SessionStart hook runs auto_standup.sh, which calls sync_mail.py for a fresh sync before presenting any context. So every time I open Claude Code, I'm looking at the latest emails.

The /standup skill groups emails by thread and shows a table with subject, contact, last message date, and status (waiting for reply from X, or already replied). If a thread has both a received file and an inviata_ file, I've already replied, and the standup marks it accordingly.

The COO agent's triage reports show up in the ops dashboard under the "Email" category. Each report has a summary section at the top and the detailed point-by-point analysis below.

What It Doesn't Do

The system doesn't reply to emails for me. It drafts responses, and they're usually decent, but I always write the actual reply myself. Client relationships are too important to delegate to AI, especially when you're a one-person company and the client knows they're talking to you specifically.

It also doesn't handle high volume. My email volume is low, with one main client, a few services, and occasional inquiries. The value isn't in processing thousands of messages. It's in the intelligent triage: making sure I never miss a client's request buried in a thread, and always having full context when I sit down to reply.

I haven't missed a client email since I turned this on. That alone makes it worth the setup.


← RETURN TO SENTINEL
END OF TRANSMISSION