NorthRelayNorthRelay
Guides

Node.js Integration

Send emails from Node.js applications using Nodemailer or the NorthRelay SDK

Node.js Integration

This guide shows two approaches for sending email from Node.js: Nodemailer (SMTP) and the @northrelay/sdk package (REST API).

Using Nodemailer (SMTP)

Installation

npm install nodemailer

Basic Example

const nodemailer = require("nodemailer");

const transporter = nodemailer.createTransport({
  host: "smtp.north-pipe.ca",
  port: 587,
  secure: false, // true for port 465, false for port 587 (STARTTLS)
  auth: {
    user: process.env.NORTHRELAY_USER,
    pass: process.env.NORTHRELAY_API_KEY,
  },
});

async function sendEmail() {
  const info = await transporter.sendMail({
    from: '"My App" <notifications@yourdomain.com>',
    to: "recipient@example.com",
    subject: "Welcome to My App",
    text: "Thanks for signing up!",
    html: "<h1>Welcome!</h1><p>Thanks for signing up.</p>",
  });

  console.log("Message sent:", info.messageId);
  return info;
}

sendEmail();

TypeScript Example

import nodemailer from "nodemailer";
import type { Transporter } from "nodemailer";

const transporter: Transporter = nodemailer.createTransport({
  host: "smtp.north-pipe.ca",
  port: 587,
  secure: false,
  auth: {
    user: process.env.NORTHRELAY_USER!,
    pass: process.env.NORTHRELAY_API_KEY!,
  },
});

interface SendEmailOptions {
  to: string;
  subject: string;
  text: string;
  html?: string;
}

async function sendEmail(options: SendEmailOptions) {
  const info = await transporter.sendMail({
    from: `"My App" <${process.env.NORTHRELAY_FROM}>`,
    to: options.to,
    subject: options.subject,
    text: options.text,
    html: options.html,
  });

  return info;
}

Using @northrelay/sdk (REST API)

Installation

npm install @northrelay/sdk

Basic Example

import { NorthRelayClient } from "@northrelay/sdk";

const client = new NorthRelayClient({
  apiKey: process.env.NORTHRELAY_API_KEY!,
});

async function sendEmail() {
  const result = await client.emails.send({
    from: { email: "notifications@yourdomain.com", name: "My App" },
    to: [{ email: "recipient@example.com" }],
    content: {
      subject: "Welcome to My App",
      text: "Thanks for signing up!",
      html: "<h1>Welcome!</h1><p>Thanks for signing up.</p>",
    },
  });

  console.log("Email queued:", result.data.messageId, result.data.status);
  return result.data;
}

sendEmail().catch(console.error);

Sending to Multiple Recipients

const result = await client.emails.send({
  from: { email: "notifications@yourdomain.com" },
  to: [{ email: "alice@example.com" }, { email: "bob@example.com" }],
  content: {
    subject: "Team Update",
    text: "Here is the weekly team update.",
  },
});

A message takes at most 100 distinct recipients across to, cc and bcc.

Sending a Template

const result = await client.emails.sendTemplate(
  "template_id",
  [{ email: "jane@example.com", name: "Jane" }],
  { first_name: "Jane", order_id: "1234" },
  { from: { email: "orders@yourdomain.com" } }
);

Error Handling

Nodemailer Error Handling

import nodemailer from "nodemailer";

const transporter = nodemailer.createTransport({
  host: "smtp.north-pipe.ca",
  port: 587,
  secure: false,
  auth: {
    user: process.env.NORTHRELAY_USER!,
    pass: process.env.NORTHRELAY_API_KEY!,
  },
});

async function sendEmail(to: string, subject: string, html: string) {
  try {
    const info = await transporter.sendMail({
      from: process.env.NORTHRELAY_FROM!,
      to,
      subject,
      html,
    });
    return { success: true, messageId: info.messageId };
  } catch (error: any) {
    if (error.responseCode === 535) {
      console.error("Authentication failed. Check your API key.");
    } else if (error.responseCode === 451) {
      console.error("Rate limit exceeded. Upgrade your plan or wait.");
    } else if (error.code === "ECONNREFUSED") {
      console.error("Connection refused. Check your firewall and port 587.");
    } else if (error.code === "ETIMEDOUT") {
      console.error("Connection timed out. Check network connectivity.");
    } else {
      console.error("Email send failed:", error.message);
    }
    return { success: false, error: error.message };
  }
}

SDK Error Handling

import { NorthRelayClient, NorthRelayError, RateLimitError } from "@northrelay/sdk";

const client = new NorthRelayClient({
  apiKey: process.env.NORTHRELAY_API_KEY!,
});

async function sendEmail(to: string, subject: string, html: string) {
  try {
    const result = await client.emails.send({
      from: { email: process.env.NORTHRELAY_FROM! },
      to: [{ email: to }],
      content: { subject, html },
    });
    return { success: true, messageId: result.data.messageId };
  } catch (error) {
    if (error instanceof RateLimitError) {
      console.error(`Rate limited. Retry after ${error.retryAfter} seconds.`);
    } else if (error instanceof NorthRelayError) {
      console.error(`API error [${error.code}] (${error.statusCode}): ${error.message}`);
      if (error.fixAction) {
        console.error(`Suggested fix: ${error.fixAction}`);
      }
    } else {
      console.error("Unexpected error:", error);
    }
    return { success: false };
  }
}

RateLimitError, ValidationError, AuthenticationError and the other error classes all extend NorthRelayError. See the TypeScript SDK for the full list.

Express.js Integration

Use the transporter as a singleton to reuse the SMTP connection pool across requests.

// lib/mailer.ts
import nodemailer from "nodemailer";

export const transporter = nodemailer.createTransport({
  host: "smtp.north-pipe.ca",
  port: 587,
  secure: false,
  auth: {
    user: process.env.NORTHRELAY_USER!,
    pass: process.env.NORTHRELAY_API_KEY!,
  },
  pool: true, // Enable connection pooling
  maxConnections: 5,
  maxMessages: 100,
});

export async function sendEmail(to: string, subject: string, html: string) {
  return transporter.sendMail({
    from: process.env.NORTHRELAY_FROM!,
    to,
    subject,
    html,
  });
}
// routes/auth.ts
import express from "express";
import { sendEmail } from "../lib/mailer";

const router = express.Router();

router.post("/register", async (req, res) => {
  const { email, name } = req.body;

  // ... create user in database ...

  await sendEmail(
    email,
    "Welcome!",
    `<h1>Hi ${name}!</h1><p>Welcome to our platform.</p>`
  );

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

export default router;

Environment Variables

Store your NorthRelay credentials in environment variables. Never commit API keys to source control.

# .env
NORTHRELAY_USER=your-email@example.com
NORTHRELAY_API_KEY=nr_live_xxxxxxxxxxxx
NORTHRELAY_FROM="My App <notifications@yourdomain.com>"

Load with dotenv or your framework's built-in env support:

import "dotenv/config";
// process.env.NORTHRELAY_API_KEY is now available

Add .env to your .gitignore to prevent accidental credential exposure.

On this page