Node.js7 min read

Sending Emails with Nodemailer

Send emails from Node.js using Nodemailer. Learn SMTP configuration, templates, and attachments.

Sarah Chen
December 19, 2025
0.0k0

Sending Emails with Nodemailer

Nodemailer is the standard for sending emails from Node.js.

Setup

npm install nodemailer

Basic Configuration

const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({
  host: 'smtp.gmail.com',
  port: 587,
  secure: false,  // true for 465, false for other ports
  auth: {
    user: process.env.EMAIL_USER,
    pass: process.env.EMAIL_PASS  // App password, not regular password
  }
});

Send Basic Email

async function sendEmail() {
  const info = await transporter.sendMail({
    from: '"My App" <noreply@myapp.com>',
    to: 'user@example.com',
    subject: 'Hello!',
    text: 'Plain text version',
    html: '<h1>Hello!</h1><p>This is HTML content.</p>'
  });
  
  console.log('Message sent:', info.messageId);
}

Multiple Recipients

await transporter.sendMail({
  from: '"My App" <noreply@myapp.com>',
  to: 'user1@example.com, user2@example.com',
  cc: 'cc@example.com',
  bcc: 'bcc@example.com',
  subject: 'Team Update',
  html: '<p>Hello team!</p>'
});

Attachments

await transporter.sendMail({
  from: '"My App" <noreply@myapp.com>',
  to: 'user@example.com',
  subject: 'Report',
  text: 'Please find the report attached.',
  attachments: [
    {
      filename: 'report.pdf',
      path: './reports/monthly.pdf'
    },
    {
      filename: 'image.png',
      content: Buffer.from('...'),  // Or file buffer
    },
    {
      filename: 'data.json',
      content: JSON.stringify({ data: 'value' })
    }
  ]
});

HTML Templates

function welcomeEmail(name) {
  return `
    <!DOCTYPE html>
    <html>
    <head>
      <style>
        .container { font-family: Arial, sans-serif; padding: 20px; }
        .header { color: #333; }
        .button { 
          background: #007bff; 
          color: white; 
          padding: 10px 20px; 
          text-decoration: none;
          border-radius: 5px;
        }
      </style>
    </head>
    <body>
      <div class="container">
        <h1 class="header">Welcome, ${name}!</h1>
        <p>Thanks for signing up.</p>
        <a href="https://myapp.com/verify" class="button">Verify Email</a>
      </div>
    </body>
    </html>
  `;
}

await transporter.sendMail({
  to: 'user@example.com',
  subject: 'Welcome!',
  html: welcomeEmail('Alice')
});

Email Service Class

class EmailService {
  constructor() {
    this.transporter = nodemailer.createTransport({
      host: process.env.SMTP_HOST,
      port: process.env.SMTP_PORT,
      auth: {
        user: process.env.SMTP_USER,
        pass: process.env.SMTP_PASS
      }
    });
  }
  
  async send(to, subject, html) {
    return this.transporter.sendMail({
      from: process.env.FROM_EMAIL,
      to,
      subject,
      html
    });
  }
  
  async sendWelcome(user) {
    return this.send(
      user.email,
      'Welcome!',
      welcomeEmail(user.name)
    );
  }
  
  async sendPasswordReset(email, resetUrl) {
    return this.send(
      email,
      'Password Reset',
      `<p>Click <a href="${resetUrl}">here</a> to reset your password.</p>`
    );
  }
}

module.exports = new EmailService();

Testing with Ethereal

// For development - catches emails without sending
async function createTestAccount() {
  const testAccount = await nodemailer.createTestAccount();
  
  return nodemailer.createTransport({
    host: 'smtp.ethereal.email',
    port: 587,
    auth: {
      user: testAccount.user,
      pass: testAccount.pass
    }
  });
}

const info = await transporter.sendMail({...});
console.log('Preview URL:', nodemailer.getTestMessageUrl(info));

Key Takeaway

Nodemailer sends emails via SMTP. Configure with your email provider's settings, use app passwords for Gmail. Create reusable templates and a service class for clean code. Use Ethereal for testing.

#Node.js#Email#Nodemailer#Intermediate