Home / Guides / Send Email with Node.js

How to Send Email with Node.js

Two methods: REST API with fetch (no dependencies) or SMTP with Nodemailer. Working code you can copy-paste.

Method 1: REST API with fetch

Node.js 18+ includes the built-in fetch API. No dependencies required — just a single HTTP POST request.

const response = await fetch("https://api.relaypost.dev/v1/emails/send", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer YOUR_API_KEY",
  },
  body: JSON.stringify({
    from: { email: "[email protected]", name: "Your App" },
    to: [{ email: "[email protected]" }],
    subject: "Your order has shipped",
    html: "<h1>Order Shipped</h1><p>Your package is on the way.</p>",
  }),
});

const result = await response.json();
console.log(result.data.message_id);

This works in any Node.js 18+ environment including serverless functions (AWS Lambda, Vercel, Cloudflare Workers).

Method 2: SMTP with Nodemailer

If your framework expects SMTP or you want to switch providers without code changes, use Nodemailer.

// npm install nodemailer
const nodemailer = require("nodemailer");

const transporter = nodemailer.createTransport({
  host: "smtp.relaypost.dev",
  port: 587,
  secure: false, // STARTTLS
  auth: {
    user: process.env.SMTP_USERNAME,
    pass: process.env.SMTP_PASSWORD,
  },
});

await transporter.sendMail({
  from: '"Your App" <[email protected]>',
  to: "[email protected]",
  subject: "Your order has shipped",
  html: "<h1>Order Shipped</h1><p>Your package is on the way.</p>",
});

Error handling

Always handle errors when sending email. Common failures include invalid API keys, rate limiting, and validation errors.

try {
  const response = await fetch("https://api.relaypost.dev/v1/emails/send", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": "Bearer YOUR_API_KEY",
    },
    body: JSON.stringify({
      from: { email: "[email protected]" },
      to: [{ email: "[email protected]" }],
      subject: "Hello",
      html: "<p>Hello from RelayPost</p>",
    }),
  });

  if (!response.ok) {
    const error = await response.json();
    console.error("Send failed:", error.error.code, error.error.message);
  }
} catch (err) {
  console.error("Network error:", err.message);
}

Sending with attachments

Include file attachments by base64-encoding the content and adding it to the attachments array.

const fs = require("fs");

const response = await fetch("https://api.relaypost.dev/v1/emails/send", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer YOUR_API_KEY",
  },
  body: JSON.stringify({
    from: { email: "[email protected]" },
    to: [{ email: "[email protected]" }],
    subject: "Your invoice",
    html: "<p>Please find your invoice attached.</p>",
    attachments: [{
      filename: "invoice.pdf",
      content: fs.readFileSync("./invoice.pdf").toString("base64"),
      type: "application/pdf",
    }],
  }),
});

Express.js example

A complete Express route that sends a welcome email after user registration.

const express = require("express");
const app = express();
app.use(express.json());

app.post("/register", async (req, res) => {
  // ... create user in database ...

  await fetch("https://api.relaypost.dev/v1/emails/send", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + process.env.RELAYPOST_API_KEY,
    },
    body: JSON.stringify({
      from: { email: "[email protected]", name: "YourApp" },
      to: [{ email: req.body.email }],
      subject: "Welcome to YourApp",
      html: "<h1>Welcome!</h1><p>Your account is ready.</p>",
    }),
  });

  res.json({ success: true });
});

app.listen(3000);

Best practices

  • Store API keys in environment variables, never in source code
  • Set up SPF and DKIM for your sending domain before sending production email
  • Include both html and text versions for maximum compatibility
  • Handle errors gracefully — queue failed sends for retry
  • Use webhooks to track delivery status instead of polling
  • Keep email sending out of the request path — use a background job queue for non-critical emails

Frequently asked questions

What is the easiest way to send email with Node.js?

The easiest way is using the built-in fetch API (Node.js 18+) with a REST email service. A single HTTP POST request with your API key and JSON payload sends the email. No dependencies or SMTP configuration required.

Should I use SMTP or API for Node.js email?

Use the REST API for new projects — it is simpler, faster, and gives you access to advanced features like templates and scheduling. Use SMTP with Nodemailer if your existing codebase already uses SMTP or if you want to switch providers without code changes.

How do I send HTML email with Node.js?

Include an html field in your email payload with the HTML content. Both the REST API and Nodemailer support HTML email. For plain text fallback, also include a text field alongside the html field.

Do I need Nodemailer to send email with Node.js?

No. Nodemailer is only needed for SMTP. If you use a REST API, the built-in fetch (Node.js 18+) or any HTTP client like axios works. No email-specific library required.

Start sending email from Node.js

Free tier includes 1,000 emails per month. Get your API key in 2 minutes.

Create free account