One of the most exciting use cases for Programmable Inbox is building AI agents that handle email. In this tutorial we'll wire up a simple agent that:
- 1Receives inbound email via webhook
- 2Classifies it (support request, billing question, spam)
- 3Auto-replies to support requests using an LLM
What you'll need
- A Programmable Inbox account (or local self-hosted instance)
- Node.js 20+
- An OpenAI API key
Step 1: Create an inbox
bash
curl -X POST https://api.programmableinbox.dev/inboxes \
-H "Authorization: Bearer $API_KEY" \
-d '{"name": "support", "domain": "acme.com"}'Note the inbox ID and the address you receive back ([email protected] in sandbox mode).
Step 2: Register a webhook
bash
curl -X POST https://api.programmableinbox.dev/inboxes/{id}/webhooks \
-H "Authorization: Bearer $API_KEY" \
-d '{"url": "https://your-app.com/api/email-webhook", "events": ["message.received"]}'Step 3: Handle the webhook
ts
// app/api/email-webhook/route.ts
import { NextRequest, NextResponse } from 'next/server'
import OpenAI from 'openai'
const client = new OpenAI()
export async function POST(req: NextRequest) {
const { message } = await req.json()
const classification = await client.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{
role: 'system',
content: 'Classify this email as: support, billing, or spam. Reply with one word.',
},
{ role: 'user', content: message.body.text },
],
})
const category = classification.choices[0].message.content?.toLowerCase()
if (category === 'support') {
const reply = await client.chat.completions.create({
model: 'gpt-4o',
messages: [
{
role: 'system',
content: 'You are a helpful support agent for Acme Corp. Reply concisely and helpfully.',
},
{ role: 'user', content: message.body.text },
],
})
await fetch(`https://api.programmableinbox.dev/messages/${message.id}/reply`, {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.API_KEY}` },
body: JSON.stringify({ text: reply.choices[0].message.content }),
})
}
return NextResponse.json({ ok: true })
}Going further
This is a minimal example. In production you'd want to add:
- Signature verification on the webhook payload
- Rate limiting to avoid runaway LLM costs
- A human-in-the-loop review step for low-confidence classifications
- Thread context — pass the full conversation history to the LLM, not just the latest message
All of that is doable with the Programmable Inbox API. The full thread history for any inbox is available at GET /inboxes/{id}/threads/{threadId}/messages.