# Inbound Email Webhook Parsing with LLMs: Converting Unstructured Email to JSON

_By Tayyab Mughal, Founder & AI Chief · 11 August 2026 · 2 min read_

> How to ingest incoming customer emails via webhook, parse attachments, and use structured LLM outputs to generate clean JSON schemas for database storage.

Turn messy incoming email replies, support tickets, and invoices into strictly validated JSON records using LLM structured outputs and webhooks.

## 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.

```python
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()}
```

---

_Tags: Inbound Email, Webhooks, LLM, Python_
