The challenge of unstructured inbound email
Customer emails are messy: forwarded thread histories, Outlook signature clutter, disclaimers, and varied phrasing. Traditional regex parsers fail as soon as a customer formats their message slightly differently.
By routing inbound email webhooks through modern LLM structured outputs (via OpenAI or Anthropic tool calling with Zod/Pydantic schemas), developers extract clean, deterministic JSON every time.
Inbound Webhook Processor with Pydantic (webhook.py)
Extract customer intent, sentiment, extracted invoice details, and action items in clean JSON.
from fastapi import FastAPI, Request
from pydantic import BaseModel, Field
from openai import OpenAI
import os
app = FastAPI()
client = OpenAI()
class ParsedSupportTicket(BaseModel):
category: str = Field(description="Billing, Technical Bug, Feature Request, or General")
urgency: str = Field(description="Low, Medium, or High")
summary: str = Field(description="One-sentence summary of customer issue")
action_item: str = Field(description="Next concrete step required from support team")
@app.post("/webhooks/inbound-email")
async def handle_inbound_email(request: Request):
payload = await request.json()
email_body = payload.get("text", "")
from_address = payload.get("from", "")
completion = client.beta.chat.completions.parse(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Extract structured support ticket details from this email body."},
{"role": "user", "content": email_body}
],
response_format=ParsedSupportTicket
)
ticket = completion.choices[0].message.parsed
print(f"[TICKET] From: {from_address} | Cat: {ticket.category} | Urgency: {ticket.urgency}")
return {"status": "parsed", "data": ticket.dict()}Building AI agents that send email?
Join the SadaSend early access waitlist to get scoped API keys, recipient allowlists, and Model Context Protocol (MCP) servers upon launch.