
The notification audit post covered how to catalog your entire notification surface area with Courier's CLI and MCP server. That's a periodic review: run it once a quarter, build a hit list, fix what's broken.
This post is about what happens between audits. A customer reports they didn't get an email. A webhook fires with a delivery failure. Your PagerDuty goes off at 2am. You need to figure out what went wrong, right now, without clicking through four dashboards.
Courier's MCP server exposes 59 tools that cover the full API surface. You can investigate a delivery failure the same way you'd investigate a bug: conversationally, from your editor, with an AI agent that can pull data on demand.
If you already set up MCP for the notification audit, you're good. If not:
# Claude Codeclaude mcp add --transport http courier https://mcp.courier.com \--header api_key:YOUR_COURIER_API_KEY
Or add it to your Cursor MCP config:
{"mcpServers": {"courier": {"url": "https://mcp.courier.com","headers": {"api_key": "YOUR_COURIER_API_KEY"}}}}

Every delivery investigation follows the same three steps: find the message, read the timeline, check the data.
1. Find the message
Ask your agent to pull recent messages filtered by status or recipient:
"Show me all undeliverable messages from the last 24 hours"
The agent calls list_messages with a status filter. You get back message IDs, recipients, providers, and timestamps. If you know the recipient, filter by that instead. If you know the tenant, pass tenant_id. The point is you're narrowing the search with a question, not navigating a UI.
2. Read the timeline
Pick a failed message and trace it:
"Get me the full event history for message 1-abc123"
The agent calls get_message for the status overview, then get_message_history for the step-by-step timeline: enqueued, mapped, routed, rendered, sent, delivered (or not). Each event has a timestamp and metadata. You're looking for where the chain broke.
Common failure points:
3. Check the data
Most "mystery" failures come down to bad data. Ask the agent to pull the user's profile:
"Get the profile for user-456 and check if they have an email address"
The agent calls get_user_profile_by_id. You see exactly what's on the profile: email, phone, push tokens, custom fields. If the field the template needs is missing or malformed, that's your root cause.
For template-level issues, pull the rendered content of a sent message:
"Show me what was actually rendered for message 1-abc123"
get_message_content returns the HTML, text, and subject line that was sent to the provider. Blank fields, broken personalization, stale copy; it all shows up here.
A customer reports: "Our users on the Acme Corp tenant aren't getting onboarding emails."
The conversation might go:
user@acme-corp.internal, which is an internal domain that doesn't accept external email.Total time: a few minutes of conversation. No dashboard navigation, no context switching, no copying message IDs between tabs.
The manual loop works for one-off investigations. But if you're responsible for delivery reliability across many tenants, you want failures to investigate themselves.
Here's the pattern:
Trigger on failure. Courier can fire webhooks on delivery events. Configure a webhook for courier.message.undeliverable and courier.message.unroutable events. These hit your endpoint with the message ID, recipient, and status.
Hand it to an agent. Your webhook handler passes the message ID to an AI agent with access to Courier's MCP tools. The agent runs the same debugging loop you'd run manually:
1. get_message(message_id) → status, provider, error2. get_message_history(message_id) → full event timeline3. get_user_profile_by_id(user_id) → profile data check4. get_message_content(message_id) → rendered output
The agent inspects the results, classifies the failure (bad address, missing profile data, provider rejection, preference block, template error), and compiles a structured report.
Compile and route the report. The agent writes a summary: message ID, recipient, failure class, root cause hypothesis, suggested fix. Route this wherever your team works: a Slack channel, a PagerDuty incident, a Courier Inbox message, or all three.
Batch and digest. If you're processing hundreds of failures, you don't want hundreds of alerts. Use Courier's Automations with a digest step to batch failures over a window (15 minutes, 1 hour) and send a single summary. The agent can classify patterns across the batch: "47 failures on tenant acme-corp, all 550 bounces on @acme-corp.internal addresses" is more useful than 47 individual alerts.
The architecture looks like this:
Delivery failure webhook↓Your endpoint (Lambda, serverless function, etc.)↓AI agent with Courier MCP tools↓Structured failure report↓Courier send → Slack / Inbox / PagerDuty(optionally batched via Automations digest)
You're not building a traditional alerting pipeline with static rules. You're building an investigation pipeline where an AI agent does the same root-cause analysis a human would, at machine speed, for every failure.
The manual investigation loop works now with any MCP-compatible client: Cursor, Claude Code, VS Code, Windsurf, or any agent framework that supports MCP. Install the server, point it at your API key, and start asking questions about your delivery data.
The automated pipeline requires webhook infrastructure and an agent runtime (OpenAI Agents SDK, Claude with tool use, LangChain, or any framework that can call MCP tools programmatically). The MCP tools are the same either way; you're just changing who's asking the questions: you, or a script.

How Apple's on-device AI works, and what it changes for your users
Apple's 2026 on-device models (AFM 3) are good enough to read, rank, and summarize everything that lands on your phone, locally and for free. Here's how they actually work, in plain terms, and how a model that reads every message before your users do changes what you should send.

You can build anything now. That's exactly why you shouldn't build this.
AI made building software cheap, so the temptation is to build everything. But owning infrastructure is a permanent draw on your scarcest resource, attention. The value lives at two ends, the systems everything runs on and the product only you can make; the move is to build less, buy the opinionated platform, and let an agent operate it.

I redid every cover image on our blog in an afternoon with Claude, Ideogram, and Contentful
I refreshed 81 blog covers, two years of posts, in a single afternoon. Claude Code orchestrated the pipeline, Ideogram generated the art, and the Contentful MCP moved every post in and out. Here is the stack, and why it only took an afternoon.
© 2026 Courier. All rights reserved.