Autonomous Email Triage for a US Gear-Pump Manufacturer by Omar ShammaAutonomous Email Triage for a US Gear-Pump Manufacturer by Omar Shamma

Autonomous Email Triage for a US Gear-Pump Manufacturer

Omar Shamma

Omar Shamma

The problem

The client is a US industrial distributor that manufactures gear pumps and motors. Their core pain point was structural, not cosmetic: the same customer request could reach the factory through more than one channel at once — one sales rep forwards an inquiry while a reseller emails the same end-customer's request separately — and both would get turned into separate work orders. Two different people on the factory floor would end up building the same part for the same buyer, with nobody catching the overlap until it was expensive.
The constraint that made this hard wasn't the classification itself, it was trust. The client wanted the system to act autonomously on inquiries it was confident about, but never silently drop or mis-route one it wasn't sure of. It also had to run entirely on the client's own infrastructure — no data leaving the building — and it had to survive being pointed at a live inbox without becoming an attack surface itself: opening a phishing link or an infected attachment because it auto-processes every email that lands.

What I built

An n8n workflow that watches the client's Outlook inbox via Microsoft Graph, decides whether each new email is a real inquiry, extracts the part numbers and customer identity, checks it against inquiries received in the last 48 hours, and routes it to one of three branches: a new inquiry (auto-acknowledged and flagged to the sales team), a duplicate (flagged with a pointer to the original, no new work order), or a low-confidence review case (held for a human to confirm). Every decision the workflow makes carries a confidence score, and low-confidence decisions never proceed on their own — they go to a person.
I also scoped and partly built a sibling system, Baby Phoenix Phone, that applies the same classify, dedup and route logic to inbound phone calls through the client's phone system, sharing the deterministic pipeline modules with the email version so a call about a part number and an email about the same part number can eventually be matched against one log.

How it works

The pipeline runs a local LLM (Ollama, gpt-oss:20b) entirely on-prem, so no customer data or part-number data leaves the client's network. Before any email reaches the model, a masking node tokenizes sender email, sender name, phone numbers, and the client's own staff identifiers — the model only ever sees placeholders, never a real address, while operational signal (part numbers, company names) stays intact because the classifier needs it.
Duplicate detection is a two-tier system: a weighted rules pass (part-number match, sender domain, subject similarity, and time proximity) produces a confidence score, and only when that score is ambiguous does it escalate to an LLM semantic comparison of the two email bodies. The two signals blend into a single verdict rather than a naive similarity threshold, because I found early on that threshold-only gates are brittle — an LLM's confidence output drifts across runs, so the safer rule was: auto-route only when both a confidence floor and an actual extracted signal (a part number or a customer name) are present.
Before any of that, every email passes a defense-in-depth security gate: regex link and attachment screening, a self-hosted ClamAV scan of attachments (I implemented the INSTREAM protocol directly against ClamAV's daemon rather than relying on a wrapper), a SHA-256 hash cross-reference against MalwareBazaar's recent-malware feed for samples ClamAV's signatures haven't caught yet, URL reputation checks against URLhaus and Google's Safe Browsing API (using privacy-preserving hash-prefix lookups so no URL is ever sent to Google), and SPF/DKIM/DMARC verdict parsing pulled from the mail headers to catch spoofed senders. If any layer can't reach its data source, the system fails closed to quarantine rather than silently skipping the check. Outbound auto-replies are stamped with a custom header so the workflow can recognise and ignore its own auto-reply if it loops back into the inbox — a real bug I found and fixed during testing.
Every threshold — confidence floors, dedup weights, which security layers are active — lives in one JSON config file the client can edit without touching the workflow, and the file is read fresh on every run so a change takes effect without a restart. A Docker sidecar refreshes the threat-intel feeds every 24 hours automatically.

Outcome

I validated all three routing branches end to end against live test emails on the client's Docker stack — new inquiries routed and auto-acknowledged, duplicates correctly matched and suppressed from creating a second work order, and low-confidence cases held for manual review — with the defence layers (malware scan, hash check, URL reputation, sender authentication) each independently tested and confirmed working, including catching a real malicious URL pulled from that day's threat feed. I also found and fixed several latent bugs during that validation, including a message-ID plumbing bug that had been silently breaking the quarantine path since the earliest version. The system moved the client from a fully manual, error-prone inbox — where an overlooked duplicate meant paying to manufacture the same part twice — to an automated pipeline ready for production cutover.

Stack

n8n, Microsoft Graph API (Outlook), Ollama (gpt-oss:20b), Docker Compose, ClamAV, URLhaus, Google Safe Browsing API, MalwareBazaar, Node.js, Git
Like this project

Posted Aug 5, 2026

n8n system that classifies, de-duplicates and answers inbound email in 15-30s on a self-hosted LLM. Zero customer-data egress behind a 5-layer security stack.