Node.js Integration

Node.js Email Testing with SendPit

Connect your Node.js application to SendPit using Nodemailer. Works with Express, NestJS, Next.js, and any Node.js framework.

Introduction

Node.js is one of the most popular runtimes for building web applications, APIs, and microservices that send email. Whether you are building a SaaS product with Express.js, a full-stack application with Next.js, or an enterprise backend with NestJS, you need a reliable way to test email delivery without sending messages to real recipients.

SendPit gives your team a private SMTP sandbox. Every email your application sends is captured, stored, and available for inspection in the SendPit dashboard. No emails reach real inboxes, no spam complaints, and no accidental data leaks. Because SendPit uses standard SMTP, you do not need a proprietary SDK. The widely-used Nodemailer library is all you need.

This guide walks you through connecting a Node.js application to SendPit step by step, with production-ready code examples for the most popular frameworks in the Node.js ecosystem.

Prerequisites

Before you begin, make sure you have:

  • Node.js 16 or later installed (run node --version to check)
  • npm or yarn as your package manager
  • A SendPit account with at least one mailbox created. You can find your SMTP credentials (username and password) on the mailbox detail page in the SendPit dashboard.

Step 1: Install Nodemailer

Nodemailer is the de facto standard for sending email from Node.js. Install it in your project:

npm install nodemailer

Or with yarn:

yarn add nodemailer

If you are using TypeScript, also install the type definitions:

npm install --save-dev @types/nodemailer

Step 2: Configure the SMTP Transport

Create a Nodemailer transport configured to point at SendPit's SMTP server. Replace the user and pass values with the credentials from your SendPit mailbox.

const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({
  host: 'smtp.sendpit.com',
  port: 587,
  secure: false, // STARTTLS upgrades the connection automatically
  auth: {
    user: 'mb_a1b2c3d4e5f6g7h8',
    pass: 'your-mailbox-password',
  },
});

Why secure: false? SendPit uses STARTTLS on port 587. Nodemailer will upgrade the connection to TLS automatically after connecting. Setting secure: true would attempt a direct TLS connection on port 465, which is not how SendPit operates.

Step 3: Send a Test Email

With the transport configured, send your first test email:

async function sendTestEmail() {
  const info = await transporter.sendMail({
    from: '"Test App" <test@example.com>',
    to: 'recipient@example.com',
    subject: 'Hello from Node.js',
    text: 'This is a plain text email sent through SendPit.',
  });

  console.log('Message sent: %s', info.messageId);
}

sendTestEmail().catch(console.error);

Run this script with node send.js. Within seconds the email will appear in your SendPit mailbox dashboard. The recipient address does not matter -- SendPit captures everything regardless of the to address.

Using Environment Variables

Never hardcode credentials in your source code. Use the dotenv package to load them from a .env file.

npm install dotenv

Create a .env file in your project root:

SMTP_HOST=smtp.sendpit.com
SMTP_PORT=587
SMTP_USER=mb_a1b2c3d4e5f6g7h8
SMTP_PASS=your-mailbox-password

Then reference these variables in your transport configuration:

require('dotenv').config();
const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({
  host: process.env.SMTP_HOST,
  port: Number(process.env.SMTP_PORT),
  secure: false,
  auth: {
    user: process.env.SMTP_USER,
    pass: process.env.SMTP_PASS,
  },
});

Add .env to your .gitignore so credentials are never committed to version control.

HTML Emails

Most transactional emails use HTML. Nodemailer makes it simple to send rich HTML content alongside a plain text fallback:

await transporter.sendMail({
  from: '"My App" <noreply@myapp.com>',
  to: 'user@example.com',
  subject: 'Welcome to My App',
  text: 'Welcome! Thanks for signing up.',
  html: `
    <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
      <h1 style="color: #333;">Welcome to My App</h1>
      <p>Thanks for signing up. Click the button below to get started.</p>
      <a href="https://myapp.com/onboarding"
         style="display: inline-block; padding: 12px 24px; background: #4F46E5;
                color: #fff; text-decoration: none; border-radius: 6px;">
        Get Started
      </a>
    </div>
  `,
});

SendPit captures both the HTML and plain text versions. You can preview the rendered HTML, view the raw source, and inspect headers directly in the dashboard.

Express.js Integration

In an Express application, create a reusable mailer module and call it from your route handlers.

// mailer.js
require('dotenv').config();
const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({
  host: process.env.SMTP_HOST,
  port: Number(process.env.SMTP_PORT),
  secure: false,
  auth: {
    user: process.env.SMTP_USER,
    pass: process.env.SMTP_PASS,
  },
});

module.exports = transporter;
// routes/contact.js
const express = require('express');
const router = express.Router();
const transporter = require('../mailer');

router.post('/contact', async (req, res) => {
  const { name, email, message } = req.body;

  try {
    await transporter.sendMail({
      from: `"${name}" <${email}>`,
      to: 'support@myapp.com',
      subject: `Contact form: ${name}`,
      text: message,
    });
    res.json({ success: true });
  } catch (error) {
    console.error('Email send failed:', error);
    res.status(500).json({ error: 'Failed to send email' });
  }
});

module.exports = router;

Every email sent through the contact form will be captured by SendPit instead of being delivered to a real support inbox.

NestJS Integration

NestJS has a dedicated mailer module that wraps Nodemailer. Install it alongside Nodemailer:

npm install @nestjs-modules/mailer nodemailer

Configure it in your application module:

// app.module.ts
import { MailerModule } from '@nestjs-modules/mailer';

@Module({
  imports: [
    MailerModule.forRoot({
      transport: {
        host: process.env.SMTP_HOST,
        port: Number(process.env.SMTP_PORT),
        secure: false,
        auth: {
          user: process.env.SMTP_USER,
          pass: process.env.SMTP_PASS,
        },
      },
      defaults: {
        from: '"My NestJS App" <noreply@myapp.com>',
      },
    }),
  ],
})
export class AppModule {}

Then inject the MailerService into any service or controller:

import { MailerService } from '@nestjs-modules/mailer';

@Injectable()
export class NotificationService {
  constructor(private readonly mailerService: MailerService) {}

  async sendWelcome(email: string, name: string) {
    await this.mailerService.sendMail({
      to: email,
      subject: 'Welcome!',
      text: `Hello ${name}, welcome aboard.`,
    });
  }
}

All emails routed through this configuration will land in your SendPit mailbox during development and testing.

Next.js API Routes

If you are using Next.js, you can send emails from API routes or server actions. Nodemailer works directly in these server-side contexts:

// app/api/send-email/route.js (App Router)
import nodemailer from 'nodemailer';

const transporter = nodemailer.createTransport({
  host: process.env.SMTP_HOST,
  port: Number(process.env.SMTP_PORT),
  secure: false,
  auth: {
    user: process.env.SMTP_USER,
    pass: process.env.SMTP_PASS,
  },
});

export async function POST(request) {
  const { to, subject, body } = await request.json();

  await transporter.sendMail({
    from: '"My App" <noreply@myapp.com>',
    to,
    subject,
    html: body,
  });

  return Response.json({ sent: true });
}

Add the SMTP variables to your .env.local file and they will be available on the server side automatically.

Testing with Jest or Vitest

In automated tests you typically want to verify that your code calls the email-sending function with the correct arguments, without actually connecting to an SMTP server. Mock the transport and assert on the calls:

// __tests__/mailer.test.js
const nodemailer = require('nodemailer');

jest.mock('nodemailer');

const sendMailMock = jest.fn().mockResolvedValue({ messageId: 'test-id' });
nodemailer.createTransport.mockReturnValue({ sendMail: sendMailMock });

const { sendWelcomeEmail } = require('../services/email');

describe('sendWelcomeEmail', () => {
  it('sends a welcome email with the correct parameters', async () => {
    await sendWelcomeEmail('user@example.com', 'Alice');

    expect(sendMailMock).toHaveBeenCalledWith(
      expect.objectContaining({
        to: 'user@example.com',
        subject: expect.stringContaining('Welcome'),
      })
    );
  });
});

For integration tests where you want to verify actual SMTP delivery, point your test environment at SendPit. Set the SMTP environment variables in your CI pipeline and use your SendPit mailbox to confirm that emails arrive as expected.

Docker Configuration

When running Node.js inside Docker, pass the SMTP credentials as environment variables through your docker-compose.yml:

services:
  app:
    build: .
    environment:
      SMTP_HOST: smtp.sendpit.com
      SMTP_PORT: 587
      SMTP_USER: mb_a1b2c3d4e5f6g7h8
      SMTP_PASS: your-mailbox-password
    ports:
      - '3000:3000'

For production-like setups, use Docker secrets or a .env file reference:

services:
  app:
    build: .
    env_file:
      - .env

Ensure that your Docker container has outbound network access to smtp.sendpit.com on port 587. If you are behind a corporate firewall or restrictive network policy, you may need to allowlist this host and port.

Troubleshooting

ECONNREFUSED

This error means your application cannot reach the SMTP server. Verify that:

  • The host is set to smtp.sendpit.com (not localhost or an internal address).
  • Port 587 is not blocked by a firewall or network policy.
  • Your DNS is resolving correctly. Run nslookup smtp.sendpit.com to confirm.

Authentication Errors (535)

A 535 Authentication failed response indicates invalid credentials. Double-check that:

  • Your username starts with mb_ and matches the value shown in the SendPit dashboard.
  • The password is copied exactly, with no trailing whitespace.
  • The credentials belong to a mailbox, not your SendPit account login.

Emails Not Appearing in Dashboard

If Nodemailer reports a successful send but you do not see the email in your SendPit mailbox:

  • Confirm you are looking at the correct mailbox. Each mailbox has its own credentials and inbox.
  • Check that the sendMail call resolved without error. Log the full response object for debugging.
  • Ensure there is no email middleware or interceptor in your application that is swallowing the send.

TLS / Certificate Errors

If you encounter TLS-related errors in development, make sure you have secure: false in your transport config. Do not set tls: { rejectUnauthorized: false } in production environments as this disables certificate validation entirely. If you need this for a local Docker setup, restrict it to development only:

const transporter = nodemailer.createTransport({
  host: process.env.SMTP_HOST,
  port: Number(process.env.SMTP_PORT),
  secure: false,
  auth: {
    user: process.env.SMTP_USER,
    pass: process.env.SMTP_PASS,
  },
  ...(process.env.NODE_ENV === 'development' && {
    tls: { rejectUnauthorized: false },
  }),
});

Timeout Errors

If connections are timing out, increase the Nodemailer connection timeout:

const transporter = nodemailer.createTransport({
  host: process.env.SMTP_HOST,
  port: Number(process.env.SMTP_PORT),
  secure: false,
  auth: {
    user: process.env.SMTP_USER,
    pass: process.env.SMTP_PASS,
  },
  connectionTimeout: 10000, // 10 seconds
  greetingTimeout: 10000,
});

Next Steps

Now that your Node.js application is connected to SendPit, you can:

  • Inspect captured emails in the SendPit dashboard -- view HTML previews, raw headers, and MIME parts.
  • Add team members to your organization so everyone can view test emails.
  • Create additional mailboxes to isolate emails by project, environment, or feature branch.
  • Integrate into CI/CD by setting SMTP credentials as pipeline secrets and verifying email delivery in your automated test suite.
  • Visit the general integration guide for examples in other languages including PHP, Python, Ruby, Java, and Go.

Looking for other languages? See the full integration guide, or read the developer documentation and explore SMTP Sandbox features.

Questions? Contact [email protected]