
Most teams can't answer a basic question about their own product: what notifications are you sending, and are they working?
This post walks through a full audit using Courier's CLI and MCP server from inside your coding environment. You'll need a free Courier API key. Every CLI command below also works as a typed MCP tool call in Cursor, Claude Code, or any agent that supports Courier's AI tooling.
npm install -g @trycourier/cliexport COURIER_API_KEY="your-api-key"
courier notifications list --format json
This returns every template, its ID, and its state (published vs. draft). If you expected 15 and there are 40, the audit was overdue.
Having a template doesn't mean it's firing. Check what's actually going out:
courier messages list --format json# Count by delivery statuscourier messages list --format json \--transform "results.#.status" | sort | uniq -c
| Status | What it means |
|---|---|
| DELIVERED | Reached the device or inbox |
| SENT | Handed to provider, not yet confirmed |
| UNDELIVERABLE | Provider rejected it (bad address, bounce, block) |
| UNROUTABLE | No valid channel found for this user |
UNDELIVERABLE and UNROUTABLE are your red flags. A handful is normal. A pattern means something is broken.
Pick a message and walk its lifecycle:
# Status overviewcourier messages retrieve --message-id "1-abc123" --format pretty# Full event timeline: enqueued, sent, delivered, opened, clickedcourier messages history --message-id "1-abc123" --format pretty# What was actually rendered and sentcourier messages output --message-id "1-abc123" --format pretty
Do this for a sample of each notification type. You're looking for where things fail (provider rejection? routing skip? preference block?) and whether the rendered content still makes sense. Stale copy, broken template variables, subject lines from 2024 -- this is where you find them.
For template-level inspection before data gets injected:
courier notifications content --notification-id "TEMPLATE_ID" --format jsoncourier notifications draft-content --notification-id "TEMPLATE_ID" --format json
If the published and draft versions have diverged, someone started editing and never shipped it.
Every notification depends on data. Cross-reference what a template expects with what's actually being passed:
# Data payload from a specific sendcourier messages retrieve --message-id "1-abc123" --format json# What's on the user's profilecourier profiles retrieve --user-id "user-123" --format json
Build a simple map per notification type: what data it needs, where that data comes from, and whether it's consistently present. This is where you find silent failures -- the notification "works" but renders with blank fields because an upstream service isn't passing everything.
For B2B products, notification health varies by customer org. list_messages accepts a tenant_id filter directly:
courier tenants list --format jsoncourier messages list --format json --tenant-id "acme-corp"courier tenants retrieve --tenant-id "acme-corp" --format json
Look for tenants with outdated brand configs, concentrated delivery failures, or notification setups that haven't been touched since onboarding.
Notifications users can't opt out of are a churn risk.
courier preferences retrieve --user-id "user-123" --format pretty
Cross-reference with your template inventory. Every non-transactional notification should have a preference topic. If your marketing digest doesn't have a toggle, you're one annoyed user away from a full unsubscribe.
Based on everything you've pulled, flag every notification that fits:
Kill it: UNDELIVERABLE/UNROUTABLE rate >10%. Zero engagement over 30 days. References features that no longer exist.
Revise it: Template variables rendering blank. Published/draft versions diverged. No preference topic assigned. Sent to channels without consent.
Batch or digest it: High volume, low urgency. Same notification type firing multiple times in minutes. Higher opt-out rates than other categories.
Investigate: Delivery rates that vary by tenant. No clear owner. Template untouched for 12+ months but still actively sending.
Take this list back to your team. The data backs up every recommendation.

Let your agent check every email before it ships
Courier Device Preview gives your coding agent real screenshots from Outlook, Gmail, and Apple Mail. Here's the prompt and workflow to have it check every email, fix the draft, and check again before you publish.

Courier vs Customer.io: 2026 messaging platform comparison
Courier and Customer.io both send across email, push, SMS, and in-app, but they are not priced or built the same way. Courier bills by the send, puts journeys, experiments, broadcasts, an in-app inbox, preferences, and 50+ delivery providers on one platform, and exposes all of it through an API, a CLI, and an MCP server. Customer.io bills by the number of profiles in your database and fits a marketing team that needs deep behavioral segmentation. This comparison covers pricing, journeys, channels, in-app messaging, localization, and preferences, with every competitor figure linked to Customer.io's own pages.

Customer messaging tools that don't need engineers
Most companies run two systems: a marketing tool for campaigns, and something else for product notifications. Here are nine tools product and growth teams can run without engineering, what still needs a developer, and what each one costs.