Skip to main content

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-replied makes 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.