joeyhbuilds · external setup guide

Inbox Triage Agent

It sorts your incoming email as it arrives, quietly marks the noise as read, and pings you only when something actually needs you. And it gets smarter every time you correct it.

Version 1.0 Updated 15 Jul 2026 Tested n8n 2.28 · Docker · macOS · Claude Haiku 4.5 · Tailscale Setup about 60 to 75 min, once
Part 1Decide if it's for you

01 Overview

What it does, and who it's for

A busy inbox mixes two very different things: mail you simply haven't opened yet, and mail that genuinely needs you to do something. The Inbox Triage Agent separates them. Every minute it checks for new mail, reads each message, and asks Claude to sort it against a growing table of your own past decisions, so it reasons from real examples instead of a rigid rule set. Noise gets marked as read automatically, so it never adds to your unread pile. Anything important triggers an instant alert on your phone. And when the AI is unsure, it asks: it sends an alert with two buttons, Suppress or Surface, and your tap is saved as a new example so it keeps getting better.

Is this for you?

If a full inbox quietly stresses you out, if you feel that pull to check every notification just in case this one matters, this is built for exactly that. It takes the deciding off your plate. The noise gets marked read and left alone, and you only get pinged for the things that genuinely need you.

You don't need to be technical. It's a little more involved than a five minute setup, about an hour, with a few command and credential steps, but every one is spelled out and any unfamiliar word has a plain explanation you can hover or tap. If you can follow steps and copy and paste, you can do this. You'll make a couple of keys and a bot along the way, and the guide walks you through each.

One honest note: it never replies to your email for you. It sorts and alerts, and every actual reply still goes through you, on purpose.

What "done" looks like

A Telegram Surface alert reading Action needed from a fabricated sender, with no buttons, the confident case.
A confident alert, a plain ping, no buttons

02 At a glance

Setup time
About 60 to 75 minutes, once
Skill level
Comfortable following steps. A few commands and keys, all spelled out
Runs on
Your own computer, on and running for real time alerts
Tools required
Docker · n8n · Gmail · an Anthropic key · a Telegram bot · Tailscale
One time cost
Free
Ongoing cost
About $1 to $4 a month for a typical personal inbox, roughly half a cent per email classified
Upkeep
Now and then, tap a button to correct a call. That tap is the training

03 What you'll need

Some tools may be new, that's fine. Any word with a dotted underline like this one has a plain explanation: hover or tap it, or find them all in the word list at the end.

  • Docker Desktop, runs n8n on your machine. From docker.com. Free.
  • n8n, the tool the whole automation is built in. You run a small custom version that can read email. The provided files handle it. Free.
  • A Gmail account with an App Password, lets the workflow read your incoming mail securely. You'll create it in Step 2. Free.
  • An Anthropic API key, from console.anthropic.com. A few dollars of credit lasts a long time.
  • A Telegram bot, how alerts reach you in real time. You'll create it with BotFather in Step 2. Free.
  • Tailscale, gives the tap to train buttons a safe address to reach your machine. From tailscale.com. Free.
  • Two workflow files. The main automation does the work: it checks for new mail, sorts each message, marks the noise as read, and sends your alerts. The tap to train handler is a small second workflow whose only job is to catch your Suppress or Surface button taps and save each one as a new example. They are separate because one is triggered by the clock, every minute, and the other by your tap in Telegram. You import both. Download them here:

Download the main workflow   Download the tap to train handler

04 Cost & security

What it costs

Building it is free. The only ongoing cost is the Claude API, and it stays small because the workflow reuses (caches) the big block of example decisions on every call, so repeat calls are billed at a fraction of the first.

One time, to buildFree
Ongoing, pay as you goEstimated $1 to $4 a month for a typical personal inbox, about half a cent per email classified (based on observed token usage, not a guarantee). Only genuinely new mail triggers a Claude call, and caching keeps each one cheap.

Your keys, your privacy

  • Your keys stay yours. Your Gmail App Password, Anthropic key, and Telegram token live only inside your own copy of n8n, stored as protected settings, never in plain view and never sent to us.
  • Never share them. Treat all three like passwords. If any one leaks, revoke it and make a new one.
  • What it can access: it reads your incoming email to sort it, marks noise as read, and sends Telegram alerts. It does not delete email, and it never sends replies.
  • What's exposed to the internet: only one thing, a single secret web address that lets Telegram deliver your button taps (Step 4). Your inbox, your dashboard, and everything else stay private.
Part 2Build it

05 Setup, four steps

1

Get n8n running

▸ about 20 minutes

Quick path

Install Docker. In an empty folder, save the Dockerfile, docker-compose.yml, and an env file below (with your real Gmail and Telegram values). Then run source ./env && docker compose up -d. Open http://localhost:5678 and create your account.

Full walkthrough
  1. Install Docker Desktop from docker.com and open it. Wait until the little whale icon is steady. To keep alerts real time, set Docker to start when you sign in.
  2. Open a terminal and make a new folder for this. Inside it, create three files. First, a file named Dockerfile (this builds a version of n8n that can read email):
    FROM docker.n8n.io/n8nio/n8n
    USER root
    RUN npm install -g imapflow mailparser
    USER node
  3. Next, a file named docker-compose.yml (this tells Docker how to run n8n):
    services:
      n8n:
        build: .
        container_name: n8n
        restart: unless-stopped
        ports:
          - "5678:5678"
        environment:
          - NODE_FUNCTION_ALLOW_EXTERNAL=imapflow,mailparser
          - NODE_FUNCTION_ALLOW_BUILTIN=fs
          - N8N_BLOCK_ENV_ACCESS_IN_NODE=false
          - N8N_EDITOR_BASE_URL=http://localhost:5678
          - GMAIL_ADDRESS=${GMAIL_ADDRESS}
          - GMAIL_APP_PASSWORD=${GMAIL_APP_PASSWORD}
          - WEBHOOK_URL=${WEBHOOK_URL}
        volumes:
          - n8n_data:/home/node/.n8n
    volumes:
      n8n_data:
  4. Finally, a file named env that holds your Gmail secrets as environment settings (you'll fill in the Gmail values in Step 2, the WEBHOOK_URL in Step 4). Your Anthropic key and Telegram bot token do not go here, they become n8n credentials in Step 3:
    export GMAIL_ADDRESS=you@gmail.com
    export GMAIL_APP_PASSWORD=your16charapppassword
    export WEBHOOK_URL=http://localhost:5678/
  5. In that folder, run source ./env && docker compose up -d. Docker builds the image and starts n8n in its own container.
  6. Open http://localhost:5678 in your web browser. That localhost address is simply your own computer, and it is the same for everyone. Create your local account there.
A terminal showing docker compose up -d, with the n8n container reporting Running.
The command run in a terminal, the container comes up
Heads up

The restart: unless-stopped line matters. Without it n8n won't come back after a reboot, and real time triage depends on it always being up. Also run source ./env before docker compose up each time, so your secrets get read in.

You'll know it worked when

http://localhost:5678 opens n8n in your web browser and the container shows as running in Docker Desktop. If not, make sure Docker is fully started and you ran the command from inside the folder with the three files.

2

Get your credentials

▸ about 20 minutes

Quick path

Create a Gmail App Password, an Anthropic API key, and a Telegram bot (via BotFather) plus your chat ID. Put the Gmail address and App Password into the env file from Step 1. Keep the Anthropic key and Telegram token handy, they become n8n credentials in Step 3.

Full walkthrough
  1. Gmail App Password. In your Google Account, Security, turn on 2 Step Verification, then create an App Password (search "App Passwords"). Copy the 16 character password. It lets the workflow read mail without your main password.
  2. Anthropic key. At console.anthropic.com, API Keys, Create Key. Copy it, and add a little credit under Billing.
  3. Telegram bot. In Telegram, message @BotFather, send /newbot, and follow the prompts. It gives you a bot token. Then get your chat ID (message @userinfobot, it replies with your number). You need both.
  4. Put the Gmail values in your env file. Open the env file from Step 1 and fill in your Gmail address and App Password. Save it, then run source ./env && docker compose up -d again so n8n picks them up. Your Anthropic key and Telegram bot token become credentials inside n8n in Step 3.
Google's App Passwords screen, with a field to name a new app password and a Create button.
Google's App Passwords screen, name it, then Create
Heads up

The App Password option only shows up after 2 Step Verification is on. Turn that on first.

You'll know it worked when

You have four things saved: your Gmail App Password, your Anthropic key, your Telegram bot token, and your Telegram chat ID. If BotFather didn't give a token, send /newbot again and pick a different bot name.

3

Import and set up the workflows

▸ about 15 minutes

Quick path

Import both files. Create an Anthropic credential and a Telegram credential in n8n, then select them on the HTTP Request box and the Telegram boxes. Set your Telegram chat ID in the alert boxes. Create the three Data Tables with the exact columns below, starting known_examples empty. Leave both workflows Inactive.

Full walkthrough
  1. Import both workflow files (menu, top right, Import from File), once each: the main Inbox Triage Agent and the Tap to Train Handler.
  2. Add your Claude key as a credential. In n8n, open Credentials (left menu), create a new one, choose Anthropic, and paste your key. Then open the box named HTTP Request (the one that calls Claude) and, under Credential, pick the one you just made.
  3. Add your Telegram bot as a credential. Create another credential, choose Telegram, and paste your bot token. Then open each Telegram box (the Surface alert and the Review alert here, and the one box in the Tap to Train Handler) and pick that credential.
  4. Set your Telegram chat ID in each Telegram box (the Surface alert, the Review alert, and the tap reply), replacing YOUR_TELEGRAM_CHAT_ID so alerts reach you.
  5. Create the three Data Tables, with these exact columns. In n8n open Data Tables, create each table, then add its columns. The names and types must match exactly, or the workflow can't read them. (In n8n's type dropdown, String just means plain text.)
    • known_examples: sender (String), subject (String), ai_guess (String), final_decision (String), reasoning (String), date (Date). This is the table it learns from. Start it empty and let it fill from your own taps over the first week, so it learns your inbox, not someone else's.
    • processed_emails: message_id (String), processed_at (Date).
    • pending_review: message_id (String), sender (String), subject (String), ai_classification (String), ai_confidence (String), ai_reasoning (String), created_at (Date).
  6. Leave both workflows Inactive for now. You'll turn them on in Testing.
The Inbox Triage workflow on the n8n canvas, a row of connected boxes ending in Telegram alert and mark-as-read steps.
The imported workflow, connected boxes, nothing to build
You'll know it worked when

Both workflows import, your Anthropic and Telegram credentials are selected on their boxes, your chat ID is set, and the three Data Tables exist with the right columns. If a Data Table box shows red, re-open it and pick the matching table by name.

4

Turn on the tap to train buttons

▸ about 15 minutes

Quick path

Install Tailscale and enable Funnel for just the one Telegram webhook address. Point WEBHOOK_URL at your Tailscale address, then restart n8n so the webhook registers.

Full walkthrough

The Suppress and Surface buttons need Telegram to reach your machine at a public web address. Tailscale Funnel gives you one safely, scoped to only the single webhook path, so nothing else is exposed.

  1. Install Tailscale from tailscale.com and sign in. Turn on Funnel for your machine in the Tailscale admin.
  2. Find your webhook address. Open the Tap to Train Handler and click the box named Telegram Trigger. It shows a web address that ends in /webhook. That address (its "webhook path") is the one thing Telegram needs to reach your machine, it is unique to your workflow. Copy the whole thing.
  3. Publish just that one address with Funnel. In the command below, wherever you see <YOUR_WEBHOOK_PATH>, paste the path part of your address, that is everything from /webhook onward, not the whole https://... part. It goes in both spots:
    tailscale funnel --bg --yes --set-path <YOUR_WEBHOOK_PATH> http://localhost:5678<YOUR_WEBHOOK_PATH>
    Tailscale prints your public address, something like https://your-machine.your-tailnet.ts.net.
  4. Put that address in your env file as WEBHOOK_URL (with a trailing slash), then restart n8n with source ./env && docker compose up -d. The restart is what actually registers the webhook so taps get delivered.
  5. Activate the Tap to Train Handler workflow.
A Telegram Review alert reading Not sure about this one, with Suppress and Surface buttons underneath.
A Review alert, the agent is unsure, so you tap Suppress or Surface
Heads up

Just activating the workflow isn't enough. The restart after setting WEBHOOK_URL is what registers the public webhook.

You'll know it worked when

Tapping a button on a Review alert clears the little spinner and replies "Marked as suppress" or "Marked as surface", and a new row appears in your known_examples table. If nothing happens, re-check that Funnel is on for the exact path ending in /webhook and that you restarted n8n.

06 Testing & going live

Prove each path before you trust it:

  1. Activate the main workflow, then send yourself an email that's clearly important. Confirm a Surface alert lands in Telegram within a minute.
  2. Send yourself an obvious piece of noise. Confirm it gets marked as read with no alert.
  3. To test tap to train, wait for (or trigger) a Review alert, tap a button, and confirm the reply and a new example row.
  4. Once all three behave, leave it Active. It now runs every minute on its own.

For the first few days, glance at the alerts and correct any it gets wrong with the buttons. That's how it tunes to your inbox.

07 What's next

joeyhbuilds · the newsletter

Get every build the moment it ships

You just set up one of the automations from joeyhbuilds, systems that do the work so you don't have to.

Subscribe and each new build reaches you the moment it's finished, the working automation, plus a guide exactly like this one.

Subscribe at joeyhbuilds.com →
Part 3Keep it running

08 Rollback & limitations

Turning it off

  • Pause for a while: toggle the main workflow Inactive. Alerts stop, and your settings and learned examples are kept.
  • Remove it fully: delete both workflows, revoke the Gmail App Password, delete the Anthropic key, revoke the bot in BotFather, and turn off Tailscale Funnel. To remove n8n entirely, delete its container.
  • What's left behind: your saved tables stay in n8n until you delete them. Your Gmail, Anthropic, and Telegram accounts are untouched.

Known limitations

It sorts and alerts, it does not reply to email for you (by design, every reply goes through you). It runs on your own machine, so it only triages while your computer and Docker are running. It judges each email fresh using your examples as reference, so a brand new sender it hasn't seen may need a correction or two before it's confident. And it works on one inbox at a time.

09 FAQ

Will it delete or archive my email?
No. Noise is only marked as read. Nothing is deleted or moved.
How does it "learn"?
Each tap on a Suppress or Surface button is saved as a new example, and every future email is judged against that growing set. No model retraining involved.
Why every minute, and will that cost a lot?
It only calls Claude when genuinely new mail arrives, and it reuses (caches) the big example block, so cost stays low.
Can I get the alerts on WhatsApp instead of Telegram?
This uses Telegram because its bots are free and take about two minutes to set up. WhatsApp does not offer that for personal use, its bot access runs through a heavier business API with an approval process, so Telegram keeps the whole thing simple.
Do I have to keep n8n open in a browser?
No. Once active and running in Docker, it works in the background.
Is my email sent anywhere?
The text of new messages is sent to Claude to sort it. Nothing is stored by us.

10 Troubleshooting

No mail is being picked up. This build reads mail with a dedicated connector rather than n8n's built in email trigger, which had a known connection bug. Make sure you're using the provided workflow and that your Gmail App Password and address are in the env file and read in.

The workflow can't read my credentials. The Code steps read your saved settings through n8n's secure accessor, which only works with N8N_BLOCK_ENV_ACCESS_IN_NODE=false in place (Step 1). Confirm that line is in your compose file, and that you ran source ./env before starting.

An important email was sorted but no Telegram message came. Make sure the chat ID is set on every Telegram box, and that you imported the provided workflow unchanged. Rewiring the alert boxes by hand can drop fields they need.

Button taps do nothing. Re-check Step 4. Funnel must be on for the exact webhook path (ending in /webhook), Tailscale must be running, and n8n must have been restarted after you set WEBHOOK_URL.

Claude returns a billing or credit error. Add credit under Billing in the Anthropic console.

Still stuck

Email support@joeyhbuilds.com and describe exactly what you see: which step, which box, and any red error text. The more specific, the faster the fix.

11 Every word, explained

New terms in one place, no need to know these before you start.

Terminal
A plain text window where you type commands. Mac: press Cmd+Space, type Terminal, then Enter. Windows: search PowerShell. You just paste in the lines we give you.
localhost
Just your own computer. A localhost web address opens a page running on your machine, not the public internet. localhost:5678 is the same for everyone here, it is n8n's default.
Docker Desktop
Free software that runs a program inside its own self contained box, so it does not interfere with the rest of your computer.
Container
The self contained box that Docker runs the program inside.
n8n
Free software for building automations by connecting steps together, no coding needed.
App Password
A special 16 character password you generate for just one app, so you never have to share your real password.
API key
A secret code that lets your automation use a paid service like Claude, and tracks your usage.
Credential
A saved login (a key or token) that n8n stores securely, so a box can use it without you retyping it each time.
Telegram bot
A little automated account on Telegram that can message you. Here it delivers your alerts and the Suppress or Surface buttons.
Chat ID
A number that tells the bot which Telegram chat to send your alerts to, yours.
Data Table
A simple table inside n8n that stores information between runs, like a mini spreadsheet.
Environment settings
Settings stored outside the workflow, so secrets like passwords are never typed into any visible field. The workflow reads them securely at run time.
Webhook
A public web address that lets another service, here Telegram, send information into your automation.
Tailscale Funnel
A Tailscale feature that publishes just one chosen web path to the internet, so Telegram can deliver your button taps while everything else stays private.