
how to build a support agent that handles email
A step-by-step guide to building an AI agent that triages your support inbox, drafts replies, and escalates what it can't handle.
Every growing company hits the same wall: the support inbox fills up faster than anyone can reply. Billing questions, technical bugs, "how do I reset my password" for the hundredth time. You hire help, build templates, write macros. It works until it doesn't.
What if your AI agent could sit on that inbox, categorize every message, draft appropriate responses, handle the easy stuff autonomously, and escalate the hard stuff to a human with full context? That's what we're building in this guide.
What we're building#
A support agent that:
- Catches customer emails at
support@yourdomain.com - Categorizes them into billing, technical, or general
- Drafts context-aware replies
- Handles routine queries on its own (password resets, FAQ answers, order status)
- Escalates anything it can't confidently resolve, with a summary for the human picking it up
We'll use the LobsterMail SDK to give the agent its own shell, then wire up the logic to triage and respond. The whole thing runs on webhooks — no polling, no cron jobs, no stale state.
Step 1: give your agent a support inbox#
First, your agent needs its own email address. Not your Gmail. Not a shared inbox with twelve years of history. A clean, isolated shell that exists just for support.
npm install @lobstermail/sdk
Then provision the inbox:
import { LobsterMail } from "@lobstermail/sdk";
const client = new LobsterMail();
const inbox = await client.provision({
name: "support",
webhookUrl: "https://your-server.com/webhook/support-inbox",
});
console.log(inbox.address);
// → support@getlobstermail.com
If you've got the Builder tier, you can use your own reef — a custom domain — so customers email support@yourcompany.com and your agent catches it directly.
Tip
Provision a separate inbox for each function. One shell for support, another for billing alerts, another for outbound. Inboxes are unlimited on the free tier, so there's no reason to cram everything into one address.
Step 2: categorize incoming emails#
When a customer emails your support address, LobsterMail fires a webhook to your server. Here's the payload your agent sees:
{
"event": "email.received",
"from": "frustrated-customer@gmail.com",
"to": "support@yourcompany.com",
"subject": "I was double charged last month",
"body": "Hi, I just noticed two identical charges on my credit card from last month. Can you look into this? My account email is jane@example.com.",
"receivedAt": "2026-02-24T14:22:00Z"
}
Now we classify it. The simplest approach is to pass the email to your LLM with a structured prompt:
import { OpenAI } from "openai";
const openai = new OpenAI();
async function categorize(email) {
const response = await openai.chat.completions.create({
model: "gpt-4o",
response_format: { type: "json_object" },
messages: [
{
role: "system",
content: `You are a support email classifier. Categorize the email into exactly one of: "billing", "technical", "general". Also rate urgency as "low", "medium", or "high". Also assess confidence from 0 to 1 — how sure you are the category is correct. Respond as JSON: { "category": "...", "urgency": "...", "confidence": 0.0, "summary": "..." }`,
},
{
role: "user",
content: `From: ${email.from}\nSubject: ${email.subject}\n\n${email.body}`,
},
],
});
return JSON.parse(response.choices[0].message.content);
}
For the double-charge email above, this returns something like:
{
"category": "billing",
"urgency": "high",
"confidence": 0.95,
"summary": "Customer reports duplicate charge on credit card. Wants investigation. Provided account email."
}
That confidence score matters. We'll use it in the next step to decide whether the agent handles the reply or hands it off.
Step 3: draft and send responses#
For high-confidence, routine queries, the agent drafts and snaps a reply directly. For anything it's unsure about, it escalates.
async function handleSupportEmail(email) {
const triage = await categorize(email);
// Low confidence or high urgency billing → escalate to a human
if (triage.confidence < 0.8 || (triage.category === "billing" && triage.urgency === "high")) {
await escalateToHuman(email, triage);
return;
}
// Draft a response using your knowledge base
const draft = await generateReply(email, triage);
// Snap the reply back to the customer
await client.send({
from: "support@yourcompany.com",
to: email.from,
subject: `Re: ${email.subject}`,
body: draft,
});
}
The generateReply function is where you bring in your knowledge base — your docs, FAQ, past tickets. Feed them into the LLM's context alongside the customer's message and category. I won't prescribe a specific RAG setup here since that depends on your stack, but the pattern is the same: retrieve relevant context, generate a reply, send it.
Tip
Start conservative. Set the confidence threshold high (0.85+) and only auto-reply to "general" category emails for the first week. Review what the agent sends. Lower the threshold and expand categories as you build trust.
Step 4: escalate with context#
When the agent can't handle something, it shouldn't just forward the raw email to a human. It should hand off a summary with everything the human needs to pick up immediately:
async function escalateToHuman(email, triage) {
const escalation = {
originalEmail: email,
category: triage.category,
urgency: triage.urgency,
summary: triage.summary,
suggestedAction: `Review ${triage.category} issue: ${triage.summary}`,
escalatedAt: new Date().toISOString(),
};
// Send to your team's internal channel — Slack, email, whatever you use
await fetch("https://hooks.slack.com/your-webhook", {
method: "POST",
body: JSON.stringify({
text: `🚨 Escalated support ticket\n*Category:* ${triage.category}\n*Urgency:* ${triage.urgency}\n*Summary:* ${triage.summary}\n*From:* ${email.from}`,
}),
});
// Also send the customer an acknowledgment so they know a human is looking
await client.send({
from: "support@yourcompany.com",
to: email.from,
subject: `Re: ${email.subject}`,
body: "Thanks for reaching out. I've flagged this for our team and someone will follow up with you shortly.",
});
}
The customer gets an immediate acknowledgment. Your team gets a structured summary. Nobody is left waiting in silence.
Step 5: wire up the webhook handler#
Tie it all together in an Express route (or whatever framework you use):
import express from "express";
const app = express();
app.post("/webhook/support-inbox", express.json(), async (req, res) => {
const email = req.body;
if (email.event === "email.received") {
// Don't block the webhook response
handleSupportEmail(email).catch(console.error);
}
res.sendStatus(200);
});
app.listen(3000);
That's the full loop. Email arrives, agent categorizes it, either replies or escalates, and the webhook returns immediately so LobsterMail knows delivery succeeded.
What this looks like in practice#
I've been running a version of this pattern for a side project. The breakdown after two weeks:
- 68% of emails were general inquiries (password resets, "how do I..." questions) that the agent handled autonomously
- 22% were billing — about half auto-resolved, half escalated
- 10% were technical bugs that always escalated with a summary
That's roughly 70% of incoming support handled without a human touching it. The humans who do get pulled in receive a structured summary instead of a raw email thread, which cuts their response time significantly.
Extending the pattern#
Once the basic loop works, there's a lot you can layer on:
- Sentiment detection — if the customer sounds angry, escalate regardless of category
- Thread awareness — check if this is a reply to an existing conversation and maintain context
- Auto-tagging in your CRM or helpdesk tool via API
- Weekly digests — have the agent email you a summary of what it handled, what it escalated, and where it was least confident
For more patterns like this, check out what agents do with email. And if you want to automate your newsletter intake alongside support, we cover that in automate your newsletter inbox.
Tip
LobsterMail is currently in pre-launch. The code examples above reflect the intended SDK design — it's built to be this simple. Join the waitlist to get early access.
Frequently asked questions
How much does it cost to run a support agent on LobsterMail?
The free tier lets your agent receive emails at no cost. Sending unlocks after verification (X post or credit card) with 10 sends/day free. The Builder plan at $9/month adds 1,000 sends/day. The LLM costs depend on your provider — most support emails are short, so token costs per email are minimal.
Can my support agent use a custom domain like support@mycompany.com?
Yes. On the Builder tier, you can bring your own reef (custom domain). Set up DNS records, and your agent catches email at whatever address you configure. See custom domains for agent email for the full setup.
What happens if the agent sends a bad reply?
Start with a high confidence threshold and limit auto-replies to low-risk categories. Review the agent's sent messages regularly. You can also add a human-approval step where the agent drafts but doesn't send until a human confirms.
Can I use a different LLM besides OpenAI?
The categorization and reply generation use standard chat completion APIs. Swap in Anthropic, Mistral, Gemini, or any model that supports structured output. The LobsterMail SDK doesn't care which LLM you use — it only handles the email layer.
How do I handle emails in languages other than English?
Most modern LLMs handle multilingual classification and response generation well. Add a language detection step to your categorization prompt, and instruct the reply generator to respond in the same language as the incoming email.
Does the agent need to stay online 24/7?
No. LobsterMail stores incoming emails in the agent's shell. If your server goes down, messages queue up and the webhook retries. When you're back online, everything catches up. No emails lost.
Can I integrate this with my existing helpdesk (Zendesk, Intercom, etc.)?
Yes. The escalation step is just an API call. Instead of posting to Slack, create a ticket in Zendesk, tag a conversation in Intercom, or hit any API endpoint. The pattern is the same — the agent triages and routes.
How do I prevent the agent from replying to spam?
Add a spam detection step before categorization. Check sender reputation, scan for common spam patterns, or use a dedicated spam filtering API. You can also configure LobsterMail to only process emails from known domains.
What if a customer replies to the agent's response?
LobsterMail delivers the reply to the same webhook. Your handler receives it as a new email.received event. You can track conversation threads by subject line or message headers and maintain context across multiple exchanges.
Can multiple agents share one support inbox?
You could, but it's better to give each agent its own shell. If you want to split support by category, provision separate inboxes — billing@yourcompany.com and technical@yourcompany.com — and let each agent own its domain.
How does this compare to using Zendesk or Intercom's built-in AI?
Those platforms bundle AI into their ecosystem. This approach gives you full control — pick your own LLM, write your own triage logic, own your data. LobsterMail handles the email infrastructure so you're not locked into any helpdesk vendor.
Is there a way to test this without real customer emails?
Yes. Provision a test inbox on LobsterMail's free tier and send yourself sample emails covering different categories and edge cases. Iterate on your prompts and confidence thresholds before pointing real traffic at it.
How fast does the webhook fire after an email arrives?
LobsterMail delivers webhook events in near real-time — typically within seconds of the email arriving in the agent's shell. Your agent can start processing before a human would even notice the notification.
Can I use this with OpenClaw?
Yes. If you're running OpenClaw, install the LobsterMail skill and your agent handles inbox provisioning on its own. The triage logic runs inside your OpenClaw instance. See give your OpenClaw agent email in 60 seconds for the full walkthrough.
Give your agent its own email. Get started with LobsterMail — it's free.