Build Support Automation
This guide walks through a complete support automation loop. A customer emails your support address. Your code classifies the message, drafts a reply, sends it back in the same thread, and escalates to a human when the model is uncertain.
The full flow runs entirely on mailbot primitives: inbound webhook → classify → reply → escalate.
Prerequisites
- a mailbot account and API key
- one inbox for support (sandbox or custom domain)
- a webhook endpoint that can receive POST requests over HTTPS
- an LLM you can call (this guide uses Anthropic Claude as an example)
Architecture
customer email
└─> mailbot inbound (message.received)
└─> your webhook
├─> classify with LLM
├─> if confident: reply via mailbot
└─> if not confident: forward to human queue
Every step is one mailbot API call. The webhook receives the inbound, you decide what to do, you call back.
Step 1: Register the webhook
Tell mailbot where to POST inbound events.
curl -X POST https://getmail.bot/v1/inboxes/$INBOX_ID/webhooks \
-H "Authorization: Bearer $MAILBOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.example.com/webhooks/mailbot",
"events": ["message.received"]
}'
mailbot will now POST a message.received event to your URL whenever a new inbound message lands on this inbox.
Step 2: Receive and verify
Your handler verifies the signature, then loads the message body.
import express from 'express';
import crypto from 'node:crypto';
import { MailBot } from '@yopiesuryadi/mailbot-sdk';
const app = express();
app.use(express.json());
const mailbot = new MailBot({ apiKey: process.env.MAILBOT_API_KEY });
app.post('/webhooks/mailbot', async (req, res) => {
const signature = req.header('X-mailbot-Signature');
const expected = crypto
.createHmac('sha256', process.env.MAILBOT_WEBHOOK_SECRET)
.update(JSON.stringify(req.body))
.digest('hex');
if (signature !== expected) {
return res.status(401).send('bad signature');
}
const event = req.body;
if (event.event_type !== 'message.received') return res.status(204).end();
await handleInbound(event);
res.status(200).end();
});
Reply with 2xx as soon as you can. Long-running work goes to a queue; the webhook handler should return fast.
Step 3: Classify
Pass the message to your LLM. Ask for a structured decision.
async function classify(message) {
const prompt = `
You are a support triage assistant. Classify the message and decide whether
to auto-reply or escalate to a human.
Subject: ${message.subject}
Body: ${message.body_text}
Respond with JSON: { "intent": "...", "confidence": 0.0-1.0, "draft": "..." }
`;
const response = await callAnthropic(prompt);
return JSON.parse(response);
}
Build a small set of intents (billing_question, bug_report, feature_request, unknown) and use them to route.
Step 4: Reply or escalate
If confidence is high, send the draft back in the same thread.
async function handleInbound(event) {
const message = await mailbot.messages.get(event.message_id);
const decision = await classify(message);
if (decision.confidence >= 0.85 && decision.intent !== 'unknown') {
await mailbot.messages.reply(message.id, {
body_text: decision.draft,
labels: ['support', 'auto-replied', decision.intent],
});
return;
}
await escalate(message, decision);
}
For escalation, the simplest pattern is to forward the inbound message to a human queue (Slack, a ticketing system, or another mailbot inbox).
async function escalate(message, decision) {
await mailbot.messages.forward(message.id, {
to: ['support-humans@yourcompany.com'],
body_text: `Auto-classifier was not confident. Intent: ${decision.intent}. Confidence: ${decision.confidence}.`,
labels: ['support', 'escalated', decision.intent],
});
}
Step 5: Close the loop
When a human replies via the support inbox, the reply lands as a normal outbound message in the same thread. The customer sees one continuous conversation. Your dashboard shows both the auto-replies and the human replies side by side.
If your team uses a separate ticketing tool, mirror replies from there back into mailbot using the Reply to message endpoint, passing the original message_id. Threading is preserved.
Practical tips
- Start with humans in the loop. Do not auto-reply on day one. Escalate everything for the first week, log the model's decisions, then raise the confidence threshold once you trust it.
- Tag every auto-reply. A label like
auto-repliedmakes it trivial to audit, filter, and rollback. - Track engagement. If the customer replies again after an auto-reply, that is a strong signal the answer was insufficient. Use engagement events and reply rate to refine prompts.
- Honor unsubscribe and opt-out. If the inbound contains keywords like "unsubscribe" or "stop", do not auto-reply — escalate.