Prompt
I'm building a Next.js app. how do I track email delivery?
Latest observation
To track email delivery in a Next.js app, you typically don’t track it directly in Next.js itself. Instead, you use your email provider’s event webhooks to receive delivery/open/click/bounce events, then store and display them in your app.
What “delivery tracking” usually means
There are a few levels:
- Accepted/Sent: your provider accepted the message
- Delivered: the recipient’s mail server accepted it
- Opened: recipient opened the email
- Clicked: recipient clicked a link
- Bounced/Deferred/Spam complaints: delivery failed or was delayed
For most apps, the important one is delivery status from the provider.
Recommended approach
1) Use an email provider that supports event webhooks
Examples:
- SendGrid
- Mailgun
- Postmark
- Resend
- AWS SES via SNS/EventBridge
These providers can send webhook events to your app when an email is delivered, bounced, opened, etc.
2) Send email with a unique message ID
When you send an email, store:
- internal user ID
- email address
- message/provider ID
- status =
queued/sent/delivered/bounced - timestamps
This lets you match webhook events back to your database record.
3) Create a Next.js API route for the webhook
In Next.js App Router, you’d create something like:
// app/api/email-webhook/route.ts
import { NextResponse } from 'next/server';
export async function POST(req: Request) {
const payload = await req.json();
// 1. Verify signature from provider if supported
// 2. Parse event type (delivered, bounced, opened, etc.)
// 3. Update your DB record
console.log(payload);
return NextResponse.json({ ok: true });
}
If your provider signs webhook payloads, verify the signature before trusting the event.
4) Update your database
Example table fields:
iduser_idto_emailprovider_message_idstatussent_atdelivered_atbounced_atopened_atclicked_aterror_reason
Example flow
- User signs up
- Your app sends a welcome email via provider
- Provider returns a message ID
- Save that message ID in your DB
- Provider sends webhook to
/api/email-webhook - Your route updates the record to
delivered - Your UI shows the current status
Important note about “open tracking”
Open tracking is less reliable now because:
- Apple Mail Privacy Protection can fake opens
- Some clients block tracking pixels
So if you care about actual delivery, rely more on:
- delivered
- bounced
- deferred
- complaint
Example with SendGrid
SendGrid can POST event data to your webhook. You can configure events such as:
- processed
- delivered
- open
- click
- bounce
- spamreport
Then your webhook route handles those events and updates your DB.
If you want simpler tracking
Use a provider with built-in event logs and just sync them into your app:
- Resend: easy DX, webhook events
- Postmark: very email-focused and reliable
- SendGrid: powerful, more complex
- SES: cheapest, but more setup
Security tips
- Verify webhook signatures
- Use idempotency so repeated events don’t double-update records
- Log raw webhook payloads for debugging
- Don’t trust client-side email status updates
If you want, I can give you a complete working example for:
- Next.js App Router + Resend
- Next.js App Router + SendGrid
- Next.js + Prisma DB schema + webhook handler