Blueprint/Chapter 9
Chapter 9

Pattern 1: Event Processing

By Zavier SandersSeptember 21, 2025

Build a complete email classifier agent that processes internal events and takes action.

Prefer something you can ship today? Start with theQuickstart: Ship One Agent with Mastra— then come back here to deepen the concepts.

Pattern Overview

Event processing is the most common agentic pattern: something happens → AI processes it → system takes action.

The Event Processing Flow

┌─────────────────────────────────────────────────────────────┐
│              EVENT PROCESSING PATTERN                       │
│                                                             │
│  1. Event Occurs                                           │
│     • Email arrives                                         │
│     • User signs up                                         │
│     • Payment completes                                     │
│                                                             │
│            ▼                                                │
│  2. Agent Processes                                        │
│     • Classify/Categorize                                  │
│     • Extract information                                  │
│     • Make decision                                         │
│                                                             │
│            ▼                                                │
│  3. System Takes Action                                    │
│     • Update database                                      │
│     • Send notification                                    │
│     • Route to team                                        │
└─────────────────────────────────────────────────────────────┘

Common Use Cases

Customer Support: Classify tickets → Route to team
Sales: New lead → Qualify and score
Operations: Invoice received → Extract and validate
Content: Blog published → Generate social posts


Example: Email Classifier Agent

The Problem

Your company receives hundreds of emails daily. Someone manually reads each and forwards to the right team (1-2 hours/day, errors common).

What we'll build: AI agent that automatically classifies and routes incoming emails.

Architecture

Email Arrives
    ↓
Webhook Receiver
    ↓
Classifier Agent
    ↓
Route to Team (Sales/Support/HR)

Setup

npm install @mastra/core @ai-sdk/openai zod
npm install @slack/web-api resend prisma

.env:

OPENAI_API_KEY=sk-...
SLACK_BOT_TOKEN=xoxb-...
RESEND_API_KEY=re_...
SALES_EMAIL=sales@company.com
SUPPORT_EMAIL=support@company.com
WEBHOOK_SECRET=your-secret

Email Ingestion

Webhook Receiver

// app/api/webhooks/email/route.ts
import { NextResponse } from 'next/server';
import { processEmail } from '@/lib/email-processor';

export async function POST(request: Request) {
  const emailData = await request.json();
  
  // Parse email
  const email = {
    id: emailData.email_id,
    from: emailData.from,
    subject: emailData.subject,
    body: emailData.text,
    receivedAt: new Date(),
  };

  // Process async (don't block webhook)
  processEmail(email).catch(console.error);

  return NextResponse.json({ success: true });
}

Classification Logic

Prompt Design

const CLASSIFIER_PROMPT = `Classify emails into: SALES, SUPPORT, HR, or SPAM.

SALES: Product inquiries, pricing, demos, partnerships
SUPPORT: Technical issues, bugs, how-to questions
HR: Job applications, recruiting
SPAM: Marketing, solicitations

Priority: HIGH (urgent/blocked), MEDIUM (standard), LOW (general)

Respond with JSON:
{
  "category": "SALES",
  "priority": "HIGH",
  "confidence": 0.95,
  "reasoning": "Enterprise demo request"
}`;

Agent Implementation

// src/mastra/agents/email-classifier.ts
import { Agent } from '@mastra/core';
import { generateObject } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';

const ClassificationSchema = z.object({
  category: z.enum(['SALES', 'SUPPORT', 'HR', 'SPAM']),
  priority: z.enum(['HIGH', 'MEDIUM', 'LOW']),
  confidence: z.number().min(0).max(1),
  reasoning: z.string(),
});

export async function classifyEmail(email: any) {
  const result = await generateObject({
    model: openai('gpt-4o-mini'),
    schema: ClassificationSchema,
    prompt: `${CLASSIFIER_PROMPT}

FROM: ${email.from}
SUBJECT: ${email.subject}
BODY: ${email.body}`,
  });

  return result.object;
}

Action Handler

Email Processor

// lib/email-processor.ts
import { classifyEmail } from '@/mastra/agents/email-classifier';
import { forwardEmail, createTicket, sendSlack } from '@/mastra/tools';

export async function processEmail(email: any) {
  // Classify
  const classification = await classifyEmail(email);

  // Skip spam
  if (classification.category === 'SPAM') return;

  // Route based on category
  switch (classification.category) {
    case 'SALES':
      await forwardEmail(email, process.env.SALES_EMAIL!);
      if (classification.priority === 'HIGH') {
        await sendSlack('#sales-alerts', `New high-priority lead from ${email.from}`);
      }
      break;

    case 'SUPPORT':
      const ticket = await createTicket(email, classification.priority);
      if (classification.priority === 'HIGH') {
        await sendSlack('#support-urgent', `Urgent ticket #${ticket.id}`);
      }
      break;

    case 'HR':
      await forwardEmail(email, process.env.HR_EMAIL!);
      break;
  }
}

Tools

// src/mastra/tools/forward-email.ts
import { Resend } from 'resend';

const resend = new Resend(process.env.RESEND_API_KEY);

export async function forwardEmail(email: any, to: string) {
  await resend.emails.send({
    from: 'classifier@company.com',
    to,
    subject: `[Classified] ${email.subject}`,
    text: `From: ${email.from}\n\n${email.body}`,
  });
}

// src/mastra/tools/send-slack.ts
import { WebClient } from '@slack/web-api';

const slack = new WebClient(process.env.SLACK_BOT_TOKEN);

export async function sendSlack(channel: string, text: string) {
  await slack.chat.postMessage({ channel, text });
}

// src/mastra/tools/create-ticket.ts
export async function createTicket(email: any, priority: string) {
  // Your ticketing system integration
  return { id: '12345' };
}

Testing

// tests/classifier.test.ts
import { classifyEmail } from '@/mastra/agents/email-classifier';

test('classifies sales inquiry', async () => {
  const email = {
    from: 'john@acme.com',
    subject: 'Demo request',
    body: 'Interested in enterprise plan',
  };

  const result = await classifyEmail(email);
  expect(result.category).toBe('SALES');
});

test('detects urgent support', async () => {
  const email = {
    from: 'customer@example.com',
    subject: 'URGENT: Cannot login',
    body: 'Blocked, need help ASAP!',
  };

  const result = await classifyEmail(email);
  expect(result.category).toBe('SUPPORT');
  expect(result.priority).toBe('HIGH');
});

Deployment

Vercel

vercel --prod
vercel env add OPENAI_API_KEY
vercel env add SLACK_BOT_TOKEN

Email Provider Setup

Configure your email provider (SendGrid, Gmail, etc.) to send webhooks to:

https://your-app.vercel.app/api/webhooks/email

Key Takeaways

  1. Event processing is simple - Receive → Process → Act
  2. Use structured outputs - generateObject for reliable JSON
  3. Process async - Don't block webhooks
  4. Route intelligently - Different actions for different categories
  5. Monitor everything - Log classifications and errors

What's Next

  • Pattern 2: External Monitoring - RSS feeds, competitor tracking
  • Pattern 3: Event Preparation - Pre-event briefings
  • Pattern 4: Scheduled Analysis - Daily/weekly reports

Get chapter updates & code samples

We’ll email diagrams, code snippets, and additions.