100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Node.js & Express Backend
25 minintermediate

Nodemailer and Transactional Email

Nodemailer and Transactional Email

Transactional emails are automated messages triggered by user actions: welcome emails, email verification, password reset links, order confirmations, and invoice attachments. In Node.js, Nodemailer is the standard library for sending email. For production delivery with guaranteed deliverability and bounce handling, you use Nodemailer with a transactional email provider such as SendGrid, Brevo (formerly Sendinblue), Mailgun, or Amazon SES.

Analogy🏏Cricket
Think of it like cricket: The BCCI doesn't personally hand-deliver scorecards to millions of fans. They use an official courier network (transactional email provider) that knows the fastest routes, confirms delivery, handles returned mail (bounces), and gives a tracking number (message ID) for every dispatch. Nodemailer is the BCCI's mail-room staff who prepare and hand the package to the courier. You still control what's in the envelope; the provider ensures it actually arrives — even if Rohit Sharma's mailbox is full (soft bounce) or his address doesn't exist (hard bounce).

Setting Up Nodemailer with a Provider

Nodemailer creates a transporter — a configured connection to an SMTP server or a provider's API. For development, Ethereal Email provides a free test inbox that captures outgoing mail without actually delivering it. For production, swap the transporter configuration to your chosen provider.

bash
npm install nodemailer
javascript
// config/mailer.js
const nodemailer = require('nodemailer');

// Development: Ethereal test account
async function createDevTransporter() {
  const testAccount = await nodemailer.createTestAccount();
  return nodemailer.createTransport({
    host:   'smtp.ethereal.email',
    port:   587,
    secure: false,
    auth: {
      user: testAccount.user,
      pass: testAccount.pass
    }
  });
}

// Production: Brevo (SMTP relay)
function createProdTransporter() {
  return nodemailer.createTransport({
    host:   'smtp-relay.brevo.com',
    port:   587,
    secure: false,
    auth: {
      user: process.env.BREVO_SMTP_LOGIN,
      pass: process.env.BREVO_SMTP_KEY
    }
  });
}

const transporter = process.env.NODE_ENV === 'production'
  ? createProdTransporter()
  : await createDevTransporter();

module.exports = transporter;
Analogy🏏Cricket
Think of it like cricket: Ethereal Email is like the team's internal practice ground — you can bowl as many deliveries as you want, the batters respond realistically, but no actual match records are kept. Production email is like a real Test match at Chepauk: the delivery (email) actually reaches the audience and goes into the official record. Use the practice ground while developing; switch to the live ground before deployment.

Sending HTML Emails with Templates

Nodemailer's sendMail accepts a mail options object with from, to, subject, text (plain-text fallback), and html. For production emails, always include both html and text fields so clients that cannot render HTML still receive readable content. Use a template engine like Handlebars or your own string interpolation for dynamic content.

Analogy🏏Cricket
🏏 Think of it like cricket: Nodemailer's sendMail options are the match's official teamsheet — from, to, subject are the fixture details every umpire needs. Crucially you submit two versions of your batting order: the polished html scorecard for the big screen and a plain text list for officials whose screen can't render graphics, just as boards post both a glossy graphic and a bare typed sheet so nobody is left guessing. Always include both, or a client that can't render HTML receives a blank card. And just as a captain doesn't rewrite the whole batting plan by hand for every opponent but slots names into a fixed template, you use a template engine like Handlebars to inject dynamic content — the player's name, the score — into a stable layout. The payoff: dual html-and-text content means every recipient can read your email, and templating means you compose the structure once and personalise it endlessly.
javascript
// utils/email.js
const transporter = require('../config/mailer');

async function sendWelcomeEmail({ to, name }) {
  const info = await transporter.sendMail({
    from:    '"SkillVeris" <[email protected]>',
    to,
    subject: 'Welcome to SkillVeris!',
    text:    'Hi ' + name + ', welcome to SkillVeris! Start your first course at https://skillveris.com/courses',
    html:    '<h2>Hi ' + name + ',</h2><p>Welcome to <strong>SkillVeris</strong>!</p><p><a href="https://skillveris.com/courses">Start learning now</a></p>'
  });

  console.log('Message sent:', info.messageId);
  // In development: console.log('Preview URL:', nodemailer.getTestMessageUrl(info));
  return info;
}

async function sendPasswordReset({ to, resetUrl }) {
  await transporter.sendMail({
    from:    '"SkillVeris" <[email protected]>',
    to,
    subject: 'Reset your password',
    text:    'Reset your SkillVeris password here: ' + resetUrl + ' (expires in 1 hour)',
    html:    '<p>Click to reset your password (expires in 1 hour):</p><p><a href="' + resetUrl + '">' + resetUrl + '</a></p>'
  });
}

module.exports = { sendWelcomeEmail, sendPasswordReset };
Lesson 27 of 36
0% complete