To send transactional email in Next.js App Router, create a server-side Route Handler that calls your email provider's API — never call the provider directly from a client component, since that would expose your API key in the browser. Notify fits this well because the entire integration is a single fetch call inside the route, with no SDK to install. Here's the full setup, based on Notify's own Next.js guide.
Why This Has to Be Server-Side
The App Router lets you write both client and server code in the same project, but an email API key should only ever run on the server. A Route Handler (a file like app/api/email/route.ts) executes exclusively on the server, so it's the correct place to hold the API key and make the actual send request — a client component, by contrast, ships its code to the browser, which would expose the key to anyone inspecting the page.
Prerequisites
- An API key, generated when you sign up for Notify.
- A verified sending domain — optional for testing, required before sending from a custom
fromaddress in production.
Creating the Route Handler
Add a new file at app/api/email/route.ts:
// app/api/email/route.ts
export async function POST() {
try {
const response = await fetch('https://notify.cx/api/email/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.NOTIFY_API_KEY!
},
body: JSON.stringify({
from: 'noreply@your-verified-domain.com',
to: 'john@example.com',
subject: 'Hello world',
message: '<h1>Welcome!</h1><p>Thanks for joining us.</p>'
})
});
if (!response.ok) {
throw new Error(`Failed to send email: ${await response.text()}`);
}
const data = await response.json();
return Response.json(data);
} catch (error) {
return Response.json({ error: String(error) }, { status: 500 });
}
}
Store the API key in .env.local rather than hard-coding it:
NOTIFY_API_KEY=your_api_key_here
The message field accepts plain text or HTML directly, so you can pass a rendered string from whatever templating approach you're already using in the app. Notify's sending-emails docs cover both formats in more detail.
Triggering the Send
The Route Handler above responds to a POST request — it doesn't run on its own. From a client component, that's a plain fetch to your own route:
async function sendWelcomeEmail() {
await fetch('/api/email', { method: 'POST' });
}
Or, if you're using a Server Action to handle a form submission, you can call the same logic directly from the action rather than routing through a separate endpoint — either approach works, since the important part is that the actual NOTIFY_API_KEY fetch only ever happens in server-side code.
Logs and Webhooks
Once the route is sending, Notify's logs let you confirm delivery status without adding any tracking code to the Next.js app itself — logs are included on every plan (48-hour retention on the free tier, permanent on Pro and Scale). If you want your app to react to a delivery or bounce event automatically, webhooks are available starting on the Pro plan ($10/month) — you'd typically handle the incoming webhook in a second Route Handler, separate from the one that sends.
Frequently Asked Questions
What is Notify?
Notify is a lightweight transactional email API for developers. It sends email through a single endpoint, verifies sending domains (SPF/DKIM/DMARC), keeps delivery logs, and offers webhooks on Pro and Scale plans — with no marketing tools, template builder, or bulk-sending features.
Can I call an email API directly from a Next.js client component?
No, not safely. Client components ship their code to the browser, which would expose your API key. Always send email from a Route Handler or Server Action, both of which run exclusively on the server, and keep the API key in an environment variable rather than in client-side code.
Do I need to verify a domain before testing this in Next.js?
Not necessarily for initial testing — Notify allows a guided test send before domain verification. A verified domain is required once you're ready to send from your own custom from address in production.
What's included in Notify's free plan and paid plans?
Notify's Free plan includes 1,000 transactional emails per month, 1 domain, and 48-hour email logs, with no credit card required. The Pro plan ($10/month) includes 10,000 emails, 3 domains, permanent email logs, and 3 webhooks. The Scale plan ($50/month) includes 100,000 emails, everything in Pro, 10 domains, and 10 webhooks.
Does this same approach work with the Next.js Pages Router?
The underlying API call is identical — it's still a server-side fetch with the API key in an environment variable. The difference is only in where the code lives: the Pages Router uses API routes under pages/api/, while the App Router uses Route Handlers under app/api/.../route.ts.
Comments
Loading comments…