How to Send Email in Node.js & TypeScript with Nodemailer & Custom SMTP
Complete guide to sending transactional emails in Node.js, Express, and Next.js using Nodemailer. Configure connection pooling, STARTTLS encryption, and integrate with CentricSell Mail's high-speed SMTP relay.
Executive Key Takeaways
- •Enable pool: true in Nodemailer to reuse SMTP connections across multiple requests, reducing latency by up to 70%.
- •Never store SMTP credentials in source code; load them via process.env.
- •CentricSell Mail provides automated multi-ESP failover behind a single Nodemailer transporter endpoint.
- •Always set both text and html properties in mailOptions to prevent spam filtering.
Table of Contents
1. Installing Nodemailer & TypeScript Types
Install Nodemailer and its TypeScript definitions:
npm install nodemailer
npm install -D @types/nodemailer
2. Configuring Connection Pooling & Transporters
Create a singleton transporter with pool: true. This keeps TCP connections open and multiplexes messages:
3. Complete TypeScript Sending Function
import nodemailer from "nodemailer";
export const mailer = nodemailer.createTransport({
host: process.env.SMTP_HOST || "smtp.centricsell.com",
port: Number(process.env.SMTP_PORT) || 587,
secure: false, // true for 465, false for 587 (STARTTLS)
auth: {
user: process.env.CENTRICSELL_API_KEY!,
pass: process.env.CENTRICSELL_API_SECRET!,
},
pool: true,
maxConnections: 5,
maxMessages: 100,
});
export async function sendEmail({
to,
subject,
html,
text,
}: {
to: string;
subject: string;
html: string;
text: string;
}) {
const info = await mailer.sendMail({
from: '"CentricSell Mail" <support@yourdomain.com>',
to,
subject,
text,
html,
});
return info.messageId;
}
4. Sending from Next.js 15 Server Actions
"use server";
import { sendEmail } from "@/lib/email";
export async function handleContactForm(formData: FormData) {
const email = formData.get("email") as string;
const message = formData.get("message") as string;
await sendEmail({
to: "team@yourdomain.com",
subject: "New Customer Inquiry",
text: `From: ${email}\nMessage: ${message}`,
html: `<p><strong>From:</strong> ${email}</p><p>${message}</p>`,
});
return { success: true };
}
5. Production Best Practices & Error Handling
- Always verify connection health during application startup using
mailer.verify(). - Log
info.messageIdandinfo.responseto correlate with delivery webhooks. - Catch
Error: Connection timeoutand retry with exponential backoff.
Automate Developer Integration in 5 Minutes
Stop manually wrestling with DNS records and server configs. CentricSell Mail runs automated pre-flight deliverability checks, provisions dedicated servers over SSH, and routes traffic across Amazon SES, SendGrid, and Mailgun.
Frequently Asked Questions
Why should I use connection pooling in Nodemailer?
Without pooling, Nodemailer establishes a new TCP and TLS handshake for every single email, adding 300ms+ of overhead per send. With pool: true, open connections are kept alive and reused.
Does Nodemailer work with Next.js App Router and Server Actions?
Yes! Nodemailer can be called directly inside Server Actions ('use server') or API Route handlers in Next.js.
Ready to scale your transactional & bulk email?
Get started with CentricSell Mail in minutes. Bring your existing AWS SES, SendGrid, or Mailgun credentials, or deploy onto your own dedicated VPS with verified SPF, DKIM, and rDNS.