Send emails with Next.js

In this quickstart, you'll learn how to send transactional emails from your Next.js 13, 14, or 15 (App Router) app with Sidemail. You'll set up the SDK, send your first email, and see examples for common use cases like welcome emails, password resets, and server actions.

Note: The Sidemail SDK is designed for server-side usage only. Use it in Route Handlers, Server Actions, or Server Components. Do not use it in Client Components.

Before you start

  1. Create a Sidemail account → get your API key
  2. Add a sending domain → set up your domain for sending

1. Install

npm install sidemail

2. Configure API key

Add your Sidemail API key to .env.local:

SIDEMAIL_API_KEY=your-api-key

3. Setup client

Create a shared instance of the Sidemail client.

// lib/sidemail.js
import configureSidemail from "sidemail";

const sidemail = configureSidemail({
	apiKey: process.env.SIDEMAIL_API_KEY,
});

export default sidemail;

4. Send a welcome email

Send an email when a user registers using a Route Handler.

// app/api/register/route.js
import { NextResponse } from "next/server";
import sidemail from "@/lib/sidemail";

export async function POST(request) {
	const { email, name } = await request.json();

	// ... create user in database ...

	await sidemail.sendEmail({
		toAddress: email,
		fromAddress: "[email protected]",
		fromName: "Your App",
		templateName: "Welcome",
		templateProps: { firstName: name },
	});

	return NextResponse.json({ message: "User registered" });
}

5. Send a password reset email

// app/api/auth/forgot-password/route.js
import { NextResponse } from "next/server";
import sidemail from "@/lib/sidemail";

export async function POST(request) {
	const { email } = await request.json();
	const token = "secure-reset-token"; // Generate this securely

	await sidemail.sendEmail({
		toAddress: email,
		fromAddress: "[email protected]",
		fromName: "Your App",
		templateName: "Password Reset",
		templateProps: {
			actionUrl: `https://myapp.com/reset/${token}`,
		},
	});

	return NextResponse.json({ message: "Reset email sent" });
}

6. Send a weekly report (Cron Job)

Next.js doesn't have a built-in scheduler. Instead, you create an API route and trigger it using an external service like Vercel Cron, GitHub Actions, or a standard cron job.

// app/api/cron/weekly-report/route.js
import { NextResponse } from "next/server";
import sidemail from "@/lib/sidemail";

export async function GET() {
	// In a real app, fetch this from your database
	const newSignups = 150;
	const chartData = [100, 200, 300, 400, 200, 300, 200, 500];

	await sidemail.sendEmail({
		toAddress: "[email protected]",
		fromAddress: "[email protected]",
		fromName: "My App",
		templateName: "Weekly Report",
		templateProps: {
			signups: newSignups,
			chart: chartData,
		},
	});

	return NextResponse.json({ message: "Weekly report sent" });
}

7. Send email via Server Action

Send an email directly from a form submission using Server Actions.

// app/actions.js
"use server";

import sidemail from "@/lib/sidemail";

export async function sendInvoice(formData) {
	const email = formData.get("email");

	await sidemail.sendEmail({
		toAddress: email,
		fromAddress: "[email protected]",
		fromName: "Your App",
		subject: "Your Invoice",
		text: "Here is your invoice.",
	});
}

8. Send HTML email

// app/api/send-html/route.js
import { NextResponse } from "next/server";
import sidemail from "@/lib/sidemail";

export async function POST(request) {
	const { email } = await request.json();

	const htmlContent = `
      <div>
        <h1>Invoice</h1>
        <p>Amount due: $99</p>
      </div>
    `;

	await sidemail.sendEmail({
		toAddress: email,
		fromAddress: "[email protected]",
		fromName: "Your App",
		subject: "Your Invoice",
		html: htmlContent,
	});

	return NextResponse.json({ message: "Invoice sent" });
}

9. Send Markdown email

Store your markdown content in a file and load it (learn more).

import { promises as fs } from "fs";
import path from "path";
import sidemail from "@/lib/sidemail";

export async function POST(request) {
	const templatePath = path.join(process.cwd(), "templates/emails/welcome.md");
	const markdownContent = await fs.readFile(templatePath, "utf8");

	await sidemail.sendEmail({
		toAddress: "[email protected]",
		markdown: markdownContent,
		templateProps: {
			name: "John",
			link: "https://example.com",
		},
	});

	// ...
}

10. Send plain text email

await sidemail.sendEmail({
	toAddress: "[email protected]",
	fromAddress: "[email protected]",
	fromName: "Your App",
	subject: "Hello",
	text: "Hello! 👋",
});

11. Schedule email

Send email later. Set scheduledAt to an ISO date string.

// Schedule for 1 hour from now
const scheduledAt = new Date(Date.now() + 60 * 60 * 1000).toISOString();

await sidemail.sendEmail({
	toAddress: "[email protected]",
	fromAddress: "[email protected]",
	fromName: "Your App",
	templateName: "Welcome",
	templateProps: { firstName: "Alex" },
	scheduledAt: scheduledAt,
});

12. Send with attachment

Use the sidemail.fileToAttachment helper to attach files.

import { promises as fs } from "fs";
import path from "path";
import sidemail from "@/lib/sidemail";

const pdfPath = path.join(process.cwd(), "public", "invoice.pdf");
const pdfData = await fs.readFile(pdfPath);

const attachment = sidemail.fileToAttachment("invoice.pdf", pdfData);

await sidemail.sendEmail({
	toAddress: "[email protected]",
	fromAddress: "[email protected]",
	fromName: "Your App",
	subject: "Your invoice",
	text: "See attached.",
	attachments: [attachment],
});

13. Handle errors

try {
	await sidemail.sendEmail({
		// ...
	});
} catch (error) {
	console.error("Sidemail error:", error.message);
	return NextResponse.json({ error: "Failed to send email" }, { status: 500 });
}