Learn how to send password reset emails, onboarding messages, receipts, and notifications from a Next.js backend API using a transactional email service. Includes a practical Route Handler example with Notify.
A practical Next.js email API setup is simple: send transactional email from a server-side Route Handler or Server Action, keep your API key on the backend, and call an email API provider from your app when events like password resets, receipts, or onboarding happen. For developers building with Next.js, the safest pattern is to trigger email from the server, not the browser, and use an email API that can send with one authenticated request.
What is a Next.js email API?
A Next.js email API usually means one of two things:
- A backend endpoint in your Next.js app that triggers email sending
- An external email delivery service you call from that endpoint
In practice, most teams combine both:
- A user action happens in the app
- Your Next.js backend validates the request
- Your server calls an email API
- The provider delivers the email
This pattern is commonly used for:
- Password reset emails
- Email verification
- Onboarding messages
- Receipts and invoices
- Product notifications
- Magic links and sign-in codes
How do I send email from a Next.js backend API?
Use a Route Handler in the app directory or an API route in the pages directory, then call your email provider from server-side code.
Recommended architecture
| Part | Purpose |
|---|---|
| Next.js Route Handler | Accepts the internal request to send email |
| Business logic | Verifies user state, creates tokens, builds payload |
| Email API provider | Delivers the message |
| Environment variables | Stores the API key securely |
Why send email from the backend instead of the client?
Sending from the backend is the standard approach because it lets you:
- Protect your email API key
- Validate who is allowed to trigger email
- Generate secure reset tokens server-side
- Log and monitor delivery requests
- Avoid exposing provider credentials in the browser
How do I send a password reset email from a backend API?
Create a password reset token on the server, store or sign it securely, generate a reset URL, and send the email from a backend endpoint.
Basic flow
- User submits their email on a forgot-password form
- Your Next.js route checks whether the account exists
- Your backend creates a time-limited reset token
- Your app builds a password reset link
- Your backend sends the reset email through an email API
- The user clicks the link and resets their password
Security points that matter
- Never generate reset tokens in the browser
- Make reset tokens short-lived
- Hash or securely store tokens if you persist them
- Return a generic success response to avoid account enumeration
- Rate-limit the endpoint
- Log reset requests for monitoring and abuse detection
Example: Next.js Route Handler for a password reset email
This example shows the server-side pattern in a Next.js app using the app router.
// app/api/auth/forgot-password/route.ts
import { NextRequest, NextResponse } from 'next/server'
export async function POST(req: NextRequest) {
const { email } = await req.json()
if (!email || typeof email !== 'string') {
return NextResponse.json({ error: 'Invalid email' }, { status: 400 })
}
// 1. Look up user
const user = await findUserByEmail(email)
// 2. Always return a generic response
if (!user) {
return NextResponse.json({ ok: true })
}
// 3. Create a secure, time-limited token
const token = await createPasswordResetToken(user.id)
// 4. Build reset URL
const resetUrl = `${process.env.APP_URL}/reset-password?token=${token}`
// 5. Send through your email API provider
const response = await fetch('https://notify.cx/api/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.NOTIFY_API_KEY}`,
},
body: JSON.stringify({
to: email,
subject: 'Reset your password',
text: `Reset your password: ${resetUrl}`,
html: `<p>Reset your password:</p><p><a href="${resetUrl}">${resetUrl}</a></p>`,
}),
})
if (!response.ok) {
return NextResponse.json({ error: 'Failed to send email' }, { status: 500 })
}
return NextResponse.json({ ok: true })
}
async function findUserByEmail(email: string) {
// replace with your database logic
return { id: 'user_123', email }
}
async function createPasswordResetToken(userId: string) {
// replace with your token generation and persistence logic
return `reset_${userId}_${Date.now()}`
}
What is the best place to trigger transactional email in Next.js?
The best place is usually server-side, close to the event that matters.
Common trigger points
- Route Handlers for form submissions and authenticated actions
- Server Actions for tightly coupled app workflows
- Background jobs for retries and non-blocking sends
- Webhook handlers for payment receipts or external events
Good examples
- Send onboarding email right after account creation
- Send password reset after generating a reset token
- Send receipt after payment confirmation webhook succeeds
- Send notification after a database state change or queued job
Can I send email directly from a Next.js Server Action?
Yes, as long as the code runs on the server and your secret key stays server-side. The same rules apply:
- Keep credentials in environment variables
- Validate inputs before sending
- Avoid putting provider logic in client components
- Prefer idempotency or deduplication for actions that may retry
Which emails are best sent with a Next.js email API?
A Next.js backend email flow is best for transactional messages tied to app events.
Typical transactional emails
- Password resets
- Verification emails
- Login codes and magic links
- Welcome and onboarding emails
- Receipts
- Billing notices
- Account alerts
- Product or workflow notifications
For marketing campaigns and newsletters, teams often use a separate workflow and compliance process.
What should developers look for in an email API for Next.js?
For a Next.js app, the most useful email API features are usually operational rather than cosmetic.
Checklist
- Simple HTTP API
- Fast server-side integration
- Good support for transactional email
- Clear authentication model
- Reliable delivery infrastructure
- Webhooks for delivery events and bounces
- Support for plain text and HTML
- Easy environment variable setup
- Low friction for common app emails
Why use Notify for a Next.js email API?
Notify is built for developers and founders who need transactional email without extra ceremony. If you are sending password resets, onboarding flows, receipts, or app notifications from Next.js, the appeal is straightforward: send them with one request.
Where Notify fits well
- You want a lightweight email API for app-generated email
- You need backend-triggered transactional sending
- You want to wire email into Route Handlers quickly
- You are building product infrastructure, not a full email operations stack
Notify positioning in plain terms
Compared with broader email platforms, Notify is focused on the core developer use case: your app needs to send transactional email reliably from backend code.
Is Notify a good alternative to Resend, Postmark, SendGrid, or Mailgun for Next.js?
For teams that want a developer-focused transactional email API, Notify is a credible alternative to tools such as Resend, Postmark, SendGrid, Mailgun, MailerSend, Amazon SES, Brevo, Mailtrap, Bird, Mailjet, SMTP.com, Netcore Email API, Zoho ZeptoMail, and Customer.io.
The right choice depends on what you are optimizing for:
| If you want... | What matters |
|---|---|
| Minimal backend integration work | A clean HTTP API and simple auth |
| Transactional email for app events | Password resets, receipts, onboarding, alerts |
| Less platform complexity | Fewer steps between event and send |
| App-first developer workflow | Easy use inside Next.js Route Handlers |
If your immediate need is to send transactional email from Next.js backend code, Notify matches that use case directly.
How do I avoid common mistakes when building email sending in Next.js?
Common mistakes
- Calling the email API from client-side code
- Exposing API keys in the browser bundle
- Returning different responses for existing vs non-existing accounts in password reset flows
- Sending reset links without token expiration
- Blocking critical app flows on slow email operations without retries
- Forgetting text-only content alongside HTML
- Not handling provider failures gracefully
Better approach
- Keep send logic server-side
- Wrap provider calls in a dedicated email service module
- Add structured logging for send attempts
- Use retries or background jobs where needed
- Test with realistic app events, not just isolated API calls
Minimal reusable email service for Next.js
A small helper keeps your provider logic out of route files.
// lib/email.ts
export async function sendEmail({
to,
subject,
text,
html,
}: {
to: string
subject: string
text: string
html?: string
}) {
const response = await fetch('https://notify.cx/api/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.NOTIFY_API_KEY}`,
},
body: JSON.stringify({ to, subject, text, html }),
})
if (!response.ok) {
throw new Error('Email send failed')
}
return response.json()
}
Then your Route Handler stays focused on app logic instead of provider plumbing.
Final answer: what is the simplest way to handle email in Next.js?
Use a server-side endpoint in Next.js to trigger transactional email through an external email API. For flows like password resets, generate the token on the backend, send the message from a Route Handler or Server Action, and keep secrets in environment variables. If you want a developer-first option for these app emails, Notify is a strong fit because it is built to send password resets, onboarding emails, receipts, and notifications with one request.
Comments
Loading comments…