Everything you need, taught through one build: an email triage agent that reads incoming email, summarizes it, and sorts it by urgency.
An email comes in. The agent reads it, writes a one line summary, and puts it into one of three buckets: must read next hour, must read next six hours, must read next 24 hours.
That's it. That's the whole task. Everything below is just how you actually build that.
Ask yourself: could I write down, in order, every step this takes, no matter what email comes in? For this task, yes. It's always the same three moves:
- Read the email
- Summarize it
- Sort it into a bucket
Because the steps never change, this is a workflow, not a full agent. That's good news. Workflows are simpler, cheaper, and easier to trust. Most first builds should be a workflow, and this one is a perfectly good place to start.
A true agent would be something like: the same task, but it also decides on its own whether to draft a reply, escalate to a person, or do nothing, and that decision changes the path each time. That's a later upgrade, not where you start.
Inside this workflow, there's exactly one moment of real decision making: sorting the email into a bucket. That's called routing. You classify the input, then send it down one of a few paths.
That's the only pattern this example needs. You don't need to learn the other four patterns (chaining, parallel work, delegating to helpers, draft then critique) to build this. They exist for more complex tasks later.
For this task, the agent needs exactly one thing: a clear instruction that tells it how to summarize and how to decide urgency. No lookups, no external actions, nothing fancy.
That instruction is called the system prompt. Here's the one this build actually uses:
You are an email triage assistant. For every email you are given, respond in exactly this format, nothing else: SUMMARY: [one sentence summary of what the email is asking or saying] URGENCY: [must read next hour, must read next six hours, or must read next 24 hours] REASON: [one short sentence on why you picked that urgency level] Guidance on urgency: - Next hour: something time sensitive, a deadline today, an angry or urgent tone, anything involving money, legal, or a system being down - Next six hours: needs a real response but nothing is actively breaking - Next 24 hours: FYI, low stakes, can wait a day with no real cost
Notice this is strict on purpose. A vague instruction gets a vague, inconsistent result. A specific format gets something you can actually use every time.
This is the whole thing, one email in, one triaged result out.
import os
from anthropic import Anthropic
client = Anthropic()
def triage_email(subject: str, body: str) -> dict:
system_prompt = """
You are an email triage assistant. For every email you are given,
respond in exactly this format, nothing else:
SUMMARY: [one sentence summary of what the email is asking or saying]
URGENCY: [must read next hour, must read next six hours, or must read next 24 hours]
REASON: [one short sentence on why you picked that urgency level]
Guidance on urgency:
- Next hour: something time sensitive, a deadline today, an angry or urgent tone,
anything involving money, legal, or a system being down
- Next six hours: needs a real response but nothing is actively breaking
- Next 24 hours: FYI, low stakes, can wait a day with no real cost
"""
message = client.messages.create(
model="claude-sonnet-5",
max_tokens=200,
system=system_prompt,
messages=[{"role": "user", "content": f"Subject: {subject}\n\nBody: {body}"}]
)
reply_text = message.content[0].text
lines = reply_text.strip().split("\n")
result = {}
for line in lines:
if line.startswith("SUMMARY:"):
result["summary"] = line.replace("SUMMARY:", "").strip()
elif line.startswith("URGENCY:"):
result["urgency"] = line.replace("URGENCY:", "").strip()
elif line.startswith("REASON:"):
result["reason"] = line.replace("REASON:", "").strip()
return result
You call it like this, with one real email:
result = triage_email(
subject="Refund not processed after 2 weeks",
body="I was told my refund would show up in 3 to 5 business days. "
"It has been 2 weeks and I still don't see it. I need this "
"resolved today or I am disputing the charge with my bank."
)
print(result)
# {'summary': 'Customer says a refund is 2 weeks late and wants it resolved today.',
# 'urgency': 'must read next hour',
# 'reason': 'Involves money and an explicit same day deadline.'}
That's a real, working build for one email. Everything after this point is just making it run automatically instead of you calling it by hand.
Right now it only handles the one email you hand it. To make it real, you'd add one more piece before the code above: a call that fetches your actual unread emails, using something like Gmail's API, and loops the triage function over each one.
This is the only genuinely new piece of code you'd need to add. Everything else in this guide already handles the harder part, which is what Claude does with each email once it has it.
Right now the result just prints to the screen. Pick one:
- A row in a spreadsheet
- A message posted to Slack
- A simple running list somewhere you check
Whichever you pick, this is a small edit at the end of the function, not a redesign of anything above.
Three real options, in order of how much setup they take:
Claude Code Routines, which trigger off things happening in a GitHub code repository (a pull request opened, a release published). Since this task is triggered by an email arriving, not a code event, Routines aren't the right tool for this one. That's a good tool for a different kind of job, like automating code review, not this.
- Decided it's a workflow, not a full agent, because the steps never change
- Used one pattern, routing, to sort into three buckets
- Wrote one strict instruction telling Claude exactly how to summarize and label
- Wrote the code that sends one email in and gets a labeled result out
- Will extend it to pull real unread email instead of one sample
- Will send the result somewhere useful instead of just printing it
- Will run it on a schedule using cron or a cloud function, not Routines
That's the entire build. Every concept from the longer notes lives inside this one example, and nothing here required learning a pattern or a tool this task doesn't actually use.