MailSlurp logo

guides

Node Send Email SMTP Guide (Nodemailer, API Sends, and Testing)

Send email with Node.js SMTP using Nodemailer, secure auth/TLS settings, HTML, attachments, API sends, and receive-side testing workflows.

If you searched for node send email smtp, send email node, node mailer, or nodemailer smtp, the production-safe path is:

  1. send from a server-side Node.js process
  2. keep SMTP credentials in environment variables
  3. use explicit TLS, timeout, and auth settings
  4. verify real inbox receipt before release
  5. inspect headers and deliverability when DNS or providers change

For package installation, version checks, and createTransport details, use the Nodemailer NPM guide. For browser JavaScript decisions, use send email with JavaScript. This page focuses on the Node SMTP implementation and test workflow.

Choose the right Node email path

Need Use Notes
Send through an SMTP provider Nodemailer SMTP Best when your team already uses SMTP credentials, relays, or provider-specific SMTP settings.
Send from a MailSlurp inbox in tests MailSlurp API send Best when you need generated inboxes, API control, and deterministic send/receive assertions.
Trigger email from frontend JavaScript Backend endpoint Keep SMTP credentials and API keys server-side; the browser should call your own backend.

Node can send the message, but the release question is whether the user-facing email arrives with the expected subject, body, links, attachments, and authentication headers.

Install Nodemailer and MailSlurp

npm install nodemailer mailslurp-client

Use Nodemailer for SMTP submission. Use MailSlurp for generated inboxes, API sends, wait-for-email assertions, received-message inspection, and CI proof.

Configure SMTP settings with environment variables

const required = (name) => {
  const value = process.env[name];
  if (!value) {
    throw new Error(`Missing ${name}`);
  }
  return value;
};

const smtpConfig = {
  host: required("SMTP_HOST"),
  port: Number(process.env.SMTP_PORT || 587),
  username: required("SMTP_USERNAME"),
  password: required("SMTP_PASSWORD"),
  from: required("SMTP_FROM_ADDRESS"),
};

Keep these values out of source control. Use separate credentials for local, staging, and production environments so a test run cannot accidentally send from a live sender identity.

Send email with Nodemailer over SMTP

const nodemailer = require("nodemailer");

const transport = nodemailer.createTransport({
  host: smtpConfig.host,
  port: smtpConfig.port,
  secure: smtpConfig.port === 465,
  auth: {
    user: smtpConfig.username,
    pass: smtpConfig.password,
  },
  connectionTimeout: 10_000,
  greetingTimeout: 10_000,
  socketTimeout: 15_000,
});

async function sendWelcomeEmail(to) {
  await transport.verify();

  return transport.sendMail({
    from: smtpConfig.from,
    to,
    subject: "Welcome to the app",
    text: "Your account is ready.",
  });
}

transport.verify() catches bad host, port, TLS, and auth combinations early. Keep it in startup checks or smoke tests so the first production user is not the first person to exercise the email path.

Send HTML email and attachments from Node

async function sendReceiptEmail(to) {
  return transport.sendMail({
    from: smtpConfig.from,
    to,
    subject: "Your receipt",
    text: "Thanks for your order. Your receipt is attached.",
    html: "<p>Thanks for your order.</p><p>Your receipt is attached.</p>",
    attachments: [
      {
        filename: "receipt.txt",
        content: Buffer.from("Order total: $42.00"),
        contentType: "text/plain",
      },
    ],
  });
}

HTML and attachments need receive-side tests. A successful SMTP response does not prove that the HTML rendered correctly, that links survived rewriting, or that attachments arrived intact.

Send email from Node with the MailSlurp API

Use MailSlurp API sends when your test workflow should create its own sender and recipient inboxes.

const { MailSlurp } = require("mailslurp-client");

const mailslurp = new MailSlurp({
  apiKey: process.env.MAILSLURP_API_KEY,
});

async function sendWithMailSlurpApi() {
  const sender = await mailslurp.createInbox();
  const recipient = await mailslurp.createInbox();

  await mailslurp.sendEmail(sender.id, {
    to: [recipient.emailAddress],
    subject: "Node API send test",
    body: "<p>This message was sent from a Node.js test.</p>",
    isHTML: true,
  });

  return { sender, recipient };
}

This is useful for integration tests, generated test accounts, demos, and release checks where you need the whole mailbox lifecycle in code.

Wait for the received email

Send success is only half the test. Wait for the recipient inbox and assert the message content.

async function assertEmailArrived(inboxId) {
  const email = await mailslurp.waitForLatestEmail(inboxId, 30_000, true);

  if (!email.subject?.includes("Node API send test")) {
    throw new Error(`Unexpected subject: ${email.subject}`);
  }

  if (!email.body?.includes("Node.js test")) {
    throw new Error("Expected body text was not found");
  }

  return email;
}

const { recipient } = await sendWithMailSlurpApi();
await assertEmailArrived(recipient.id);

Extend the assertion for customer-facing workflows:

  • check magic links and password reset URLs
  • extract OTP codes from body text or HTML
  • verify attachments are present
  • inspect SPF, DKIM, and DMARC headers
  • capture the email ID in CI logs for debugging

Start with Email integration testing when you want these checks in a repeatable test suite. Use Email Sandbox when you want isolated inboxes for local, staging, and preview environments.

Common Node SMTP errors and fixes

EAUTH or SMTP 535

Check the SMTP username, password, sender identity, app-password policy, and provider-specific SMTP AUTH settings. Also verify that the sender domain aligns with your SPF, DKIM, and DMARC posture.

Useful follow-ups:

TLS or certificate failures

Port 587 commonly uses STARTTLS with secure: false. Port 465 commonly uses implicit TLS with secure: true. Do not guess: match your provider settings and test the transport before release.

Useful follow-ups:

ETIMEDOUT, connection refused, or network blocks

Check outbound network rules, serverless runtime restrictions, corporate egress controls, and provider hostnames. Add explicit timeouts so failures are visible and bounded.

SMTP accepted the message but the inbox never received it

SMTP acceptance does not guarantee inbox placement. Run a MailSlurp receive assertion, inspect headers, and use deliverability checks when sender reputation or filtering may be involved.

Useful follow-ups:

Production checklist for Node email

  1. Keep SMTP and API credentials in server-only environment variables.
  2. Use explicit host, port, TLS, auth, and timeout settings.
  3. Verify the SMTP transporter before sending production traffic.
  4. Add receive-side assertions for signup, reset, invite, receipt, and alert emails.
  5. Check links, OTP codes, HTML, attachments, and headers, not just the send response.
  6. Monitor deliverability after DNS, template, sender, or provider changes.
  7. Use webhooks or stored email IDs to make failures easy to debug.

FAQ

Can Node.js send email with SMTP?

Yes. Node.js commonly sends SMTP email with Nodemailer. Keep credentials server-side, use explicit TLS/auth settings, and test real inbox receipt before release.

Should I use Nodemailer or a send email API?

Use Nodemailer when your workflow is built around SMTP. Use a send email API when you want API-first sender control, generated inboxes, and test automation. Many teams use both: Nodemailer for production SMTP and MailSlurp for proof that critical messages arrive.

Can browser JavaScript send SMTP email?

No, not safely. Browser JavaScript should call a backend endpoint. The backend can send with Nodemailer, MailSlurp, or another provider without exposing credentials to the browser.

How do I test Node email in CI?

Create a fresh MailSlurp inbox, trigger the same Node send path your app uses, wait for the email by inbox ID, and assert the subject, body, links, OTP codes, attachments, and headers.

Next steps