Send emails with Next.js
Learn how to send transactional emails using PostStack and Next.js.
The PostStack TypeScript SDK is a first-class fit for Next.js — fully typed, tree-shakeable, and isomorphic for the bits that need to run server-side. Always call `poststack.emails.send(...)` from a Route Handler, Server Action, or Server Component, never from a Client Component: shipping your API key to the browser would expose your account to anyone with devtools. The SDK uses the platform `fetch`, so it runs on Node.js, the Edge Runtime, and Bun-based deploys without changes.
1. Install the SDK
npm install @poststack.dev/sdk2. Initialize the client
import { PostStack } from '@poststack.dev/sdk';
const poststack = new PostStack(process.env.POSTSTACK_API_KEY!);3. Send an email
// app/api/send/route.ts
import { NextResponse } from 'next/server';
import { PostStack, PostStackError } from '@poststack.dev/sdk';
const poststack = new PostStack(process.env.POSTSTACK_API_KEY!);
export async function POST() {
try {
const { id } = await poststack.emails.send({
from: 'hello@yourdomain.com',
to: ['user@example.com'],
subject: 'Hello from Next.js!',
html: '<h1>Welcome!</h1>',
});
return NextResponse.json({ id });
} catch (err) {
if (err instanceof PostStackError) {
return NextResponse.json({ error: err.message }, { status: err.statusCode });
}
throw err;
}
}4. Handle errors
Next.js idioms for error handling, retries, and structured logging when calling the PostStack API.
import { NextResponse } from 'next/server';
import { PostStack, PostStackError } from '@poststack.dev/sdk';
const poststack = new PostStack(process.env.POSTSTACK_API_KEY!);
export async function POST(req: Request) {
const body = (await req.json()) as { to: string; subject: string; html: string };
try {
const { id } = await poststack.emails.send({
from: 'hello@yourdomain.com',
to: [body.to],
subject: body.subject,
html: body.html,
});
return NextResponse.json({ id });
} catch (err) {
if (err instanceof PostStackError) {
// Forward PostStack's status code so the client sees 422 for
// validation failures, 429 for rate limits, 5xx for upstream issues.
console.error('PostStack error', {
status: err.statusCode,
message: err.message,
requestId: err.requestId,
});
return NextResponse.json({ error: err.message }, { status: err.statusCode });
}
throw err;
}
}Framework integrations
App Router — Route Handlers
The recommended path. Create `app/api/send/route.ts` exporting an async `POST` function, build the SDK client at module scope, and `await poststack.emails.send(...)` inside the handler. Module-scope instantiation keeps the connection pool warm between requests on serverless and Edge runtimes.
App Router — Server Actions
Mark the action with `"use server"` and call `poststack.emails.send(...)` directly. Server Actions inherit the request, so you can read cookies, headers, and form data without a separate fetch hop. Use this for form-driven sends (contact, support, signup confirmation).
Edge Runtime
The SDK runs unmodified on the Edge Runtime since it relies only on the platform fetch. Set `export const runtime = "edge"` in your route file. Edge is great for lower-latency sends from globally distributed users, though the cold-start improvement is small for European-only audiences.
Pages Router (legacy)
Use `pages/api/send.ts` with a default-exported handler. Same client, same method calls — only the import surface changes (`NextApiRequest`/`NextApiResponse` instead of the App Router’s Request/Response).
Common pitfalls
Calling from a Client Component
Never call `poststack.emails.send(...)` in a `"use client"` component. The API key would ship to the browser and be visible in the bundle. Always route through a server-side handler or Server Action.
Using `NEXT_PUBLIC_` for the API key
`NEXT_PUBLIC_*` variables are exposed to the client. Use a plain `POSTSTACK_API_KEY` env var — Next.js will keep it server-only.
Recreating the client on every request
Instantiate the `PostStack` client once at module scope. Re-creating it inside the request handler discards the HTTP connection pool and adds latency under load.
FAQ
Where should I instantiate the SDK in a Next.js app?
At module scope inside the file that uses it (a Route Handler or Server Action). Module-scope instantiation lets the runtime reuse the HTTP connection pool across requests on Node and Edge.
Does the SDK work on the Edge Runtime?
Yes — it uses the platform fetch and has no Node-only dependencies. Set `export const runtime = "edge"` on your route to opt into Edge.
Can I send from a Server Action?
Yes. Mark the action with `"use server"` and call `poststack.emails.send(...)`. Server Actions are the cleanest fit for form-driven flows like contact and signup confirmations.
What about React Email for templates?
Use React Email to author templates as React components, build them with `npx react-email build`, and either upload the compiled HTML to PostStack as a named template or pass it inline on each send.
Related guides
Ready to send emails with Next.js?
Create a free account and get your API key in under a minute.