When you run a company alone, email is where work arrives. Clients send change requests, approve deliverables, ask for quotes, and shift priorities there. If I miss one message from a client, I can end up explaining why the feature they asked for two weeks ago has not even started.
I built a system that syncs, classifies, analyzes, and surfaces my email every morning with full context. It does not reply for me. I would never trust AI with client correspondence, but it handles everything else.
The Sync Layer
A Python script called sync_mail.py runs every 30 minutes via a macOS LaunchAgent. The script reads directly from Apple Mail using JXA (JavaScript for Automation) through osascript. There is no IMAP parsing and no external libraries.
The source is the iCloud account, specifically the "subralabs" mailbox. Each run handles up to 50 messages, with the body truncated at 10,000 characters. The sync is bidirectional: it pulls both received emails and emails I have sent from [email protected]. The sent mail sync tries multiple mailbox names because locale settings vary: "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 use an inviata_ prefix in the filename. That prefix matters later when the system works out which threads I have already answered.
Classification and Threading
Every email is sorted into project folders by keyword rules:
mail/arabia/matches keywords like "arabia", "saudi", "atlas", "heritage", "testflight", "beta 3", plus the client's email addressmail/resorts/matches "resorts", "magazine", "rivista"mail/subralabs/matches "subralabs", "subra labs", "sito", "cloudflare"mail/generale/is the fallback for everything else
A message can land in more than one folder when it matches multiple rules. All email files are gitignored and never touch GitHub. Privacy is not negotiable.
Threading stays simple. A slugify() function takes the subject line, strips prefixes such as "Re:", "Fwd:", "R:", and "I:", normalizes the text, and produces a slug. The slug becomes part of the filename and the Thread field in each markdown file. 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
I do not parse RFC message-ID headers. That would be more "correct", but the added complexity is not 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 scheduling autonomous tasks. It is the system's brain. From there, the agent reads all emails from the last 3 days, matches received emails with sent emails on the same thread, and works out whether I have already replied.
Then it analyzes each client email point by point. It extracts and annotates every request, decision, priority change, financial mention, deadline, and preference. The analysis extends to 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 has 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 are flagged as URGENT. The agent drafts responses in my writing style, formal with clients, signed "Cordiali saluti, Martino Vigiani, SubraLabs". Pending actions also become tasks in the shared task system.
How It Fits Into My Daily Workflow
The email triage is part of the session lifecycle in several places.
At SessionStart, the hook runs auto_standup.sh, which calls sync_mail.py for a fresh sync before it presents any context. Every time I open Claude Code, I am 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 have already replied and the standup marks it accordingly.
COO triage reports appear in the ops dashboard under the "Email" category. Each report starts with a summary section and then the detailed point by point analysis.
What It Doesn't Do
The system does not reply to emails for me. It drafts responses, and they are usually decent, but I always write the actual reply myself. Client relationships are too important to delegate to AI, especially when you run a company of one and the client knows they are talking to you specifically.
High volume is outside its scope. My email volume is low, with one main client, a few services, and occasional inquiries. The value is not in processing thousands of messages. It is in the intelligent triage: making sure I do not miss a client's request buried in a thread and always have 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.