How to Send Dynamic Emails with Next.js, TypeScript, and Nodemailer

Manish Tamang

Manish Tamang / August 10, 2024

4 min readNaN views

In this tutorial, I'll walk you through the steps to create a simple email-sending feature using Next.js, TypeScript, and Nodemailer. We'll be creating a form that captures user input and then sends a dynamic email to the provided address. Let's dive in!

Setting Up the Project

First, ensure you have a Next.js project set up. If you don't, you can quickly create one by running:


npx create-next-app@latest

Navigate to your project directory:


cd your-project-name

Next, install the required dependencies:


npm install nodemailer

We'll be using Gmail's SMTP server to send emails. For that, you'll need to create an .env file at the root of your project and add your Gmail credentials:


GMAIL_USER="your-email@gmail.com"
GMAIL_PASS="your-app-password"

Note It's recommended to use an App Password instead of your regular password for security reasons. You can generate one from your Google Account settings.

Creating the Email Form Component

Let's start by creating a simple form in app/page.tsx. This form will take the user's name and email address:


"use client";
import { useState } from "react";
export default function SimpleForm() {
const [name, setName] = useState<string>("");
const [email, setEmail] = useState<string>("");
const [message, setMessage] = useState<string>("");
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const res = await fetch("/api/send-email", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ name, email }),
});
const data = await res.json();
if (res.ok) {
setMessage("Email sent successfully!");
} else {
setMessage(`Error: ${data.error}`);
}
};
return (
<div className="max-w-md mx-auto mt-10">
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700">
Name
</label>
<input
type="text"
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
value={name}
onChange={(e) => setName(e.target.value)}
required
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Email
</label>
<input
type="email"
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
<button
type="submit"
className="w-full py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Submit
</button>
</form>
{message && <p className="mt-4 text-center">{message}</p>}
</div>
);
}

This component handles the form submission and sends a POST request to our API route with the user's name and email.

Creating the API Route to Send Emails

Next, let's create an API route that will handle the email-sending logic. In your app/api/send-email/route.ts file, add the following code:


import nodemailer from "nodemailer";
import { NextResponse } from "next/server";
const transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: process.env.GMAIL_USER,
pass: process.env.GMAIL_PASS,
},
});
export async function POST(request: Request) {
try {
const { name, email } = await request.json();
if (!name || !email) {
return NextResponse.json(
{ error: "Name and email are required" },
{ status: 400 }
);
}
const emailContent = `
Hello ${name}!
This is a test email.
Thank you!
`;
await transporter.sendMail({
from: process.env.GMAIL_USER,
to: email,
subject: "Test Dynamic Email",
text: emailContent,
});
return NextResponse.json({ message: "Email sent successfully" });
} catch (error) {
console.error("Error in send-email API:", error);
return NextResponse.json(
{ error: "Failed to send email" },
{ status: 500 }
);
}
}

This code sets up a Nodemailer transporter using Gmail's SMTP service. It listens for POST requests, extracts the name and email from the request body, and sends a simple email with the provided details.

Testing the Email Form

With everything set up, start your Next.js development server:


npm run dev

Navigate to http://localhost:3000 in your browser. You should see the form we created earlier. Fill in your name and email, and hit "Submit." If everything is configured correctly, you should receive an email in your inbox shortly!

Conclusion

In this tutorial, we built a simple form that sends dynamic emails using Next.js, TypeScript, and Nodemailer. This basic setup can be extended with more complex email templates, additional form fields, or even a database integration for storing email records.

Feel free to experiment and adapt the code to fit your project's needs. Happy coding!

Make sure you followed me in Instagram and here is Guestbook for any reviews about me.