Last updated: 2025-01-228 min read

Send Email with Node.js: Complete Guide

Learn how to send transactional emails with Node.js using the Truncus SDK. This guide covers setup, basic sending, templates, and error handling.

Prerequisites

Installation

Install the Truncus Node.js SDK:

npm install @truncus/node

Or with other package managers:

# Yarn
yarn add @truncus/node

# pnpm
pnpm add @truncus/node

Basic Setup

Initialize the client with your API key:

import { Truncus } from '@truncus/node';

const truncus = new Truncus({
  apiKey: process.env.TRUNCUS_API_KEY,
});

Send Your First Email

Send a simple HTML email:

const { data, error } = await truncus.emails.send({
  from: 'hello@yourdomain.com',
  to: 'user@example.com',
  subject: 'Welcome to our platform',
  html: '<h1>Welcome!</h1><p>Thanks for signing up.</p>',
});

if (error) {
  console.error('Failed to send:', error.message);
  return;
}

console.log('Email sent:', data.id);

Send to Multiple Recipients

Send to multiple addresses:

await truncus.emails.send({
  from: 'notifications@yourdomain.com',
  to: ['user1@example.com', 'user2@example.com'],
  subject: 'Team update',
  html: '<p>Here is your weekly summary.</p>',
});

Add CC and BCC:

await truncus.emails.send({
  from: 'billing@yourdomain.com',
  to: 'customer@example.com',
  cc: ['accounts@customer.com'],
  bcc: ['records@yourdomain.com'],
  subject: 'Invoice #1234',
  html: invoiceHtml,
});

Using Reply-To

Set a different reply address:

await truncus.emails.send({
  from: 'noreply@yourdomain.com',
  replyTo: 'support@yourdomain.com',
  to: 'user@example.com',
  subject: 'Your support ticket',
  html: ticketHtml,
});

Plain Text Fallback

Always include a plain text version for accessibility:

await truncus.emails.send({
  from: 'hello@yourdomain.com',
  to: 'user@example.com',
  subject: 'Account verification',
  html: '<p>Your code is: <strong>123456</strong></p>',
  text: 'Your code is: 123456',
});

Sending with Attachments

Attach files to your email:

import { readFileSync } from 'fs';

await truncus.emails.send({
  from: 'billing@yourdomain.com',
  to: 'customer@example.com',
  subject: 'Your invoice',
  html: '<p>Please find your invoice attached.</p>',
  attachments: [
    {
      filename: 'invoice.pdf',
      content: readFileSync('./invoice.pdf'),
    },
  ],
});

Custom Headers

Add custom email headers:

await truncus.emails.send({
  from: 'system@yourdomain.com',
  to: 'user@example.com',
  subject: 'Password reset',
  html: resetHtml,
  headers: {
    'X-Entity-Ref-ID': userId,
    'X-Priority': '1',
  },
});

Error Handling

Handle errors properly:

import { Truncus, TruncusError } from '@truncus/node';

const truncus = new Truncus({ apiKey: process.env.TRUNCUS_API_KEY });

try {
  const { data, error } = await truncus.emails.send({
    from: 'hello@yourdomain.com',
    to: 'user@example.com',
    subject: 'Test',
    html: '<p>Hello</p>',
  });

  if (error) {
    // API returned an error
    switch (error.code) {
      case 'rate_limited':
        // Wait and retry
        await sleep(error.retryAfter * 1000);
        break;
      case 'invalid_recipient':
        // Handle bad email address
        break;
      case 'domain_not_verified':
        // Domain needs verification
        break;
      default:
        console.error('Send failed:', error.message);
    }
    return;
  }

  console.log('Sent:', data.id);
} catch (err) {
  // Network or unexpected error
  console.error('Unexpected error:', err);
}

TypeScript Support

The SDK is fully typed. Import types as needed:

import { Truncus, SendEmailRequest, SendEmailResponse, TruncusError } from '@truncus/node';

const emailRequest: SendEmailRequest = {
  from: 'hello@yourdomain.com',
  to: 'user@example.com',
  subject: 'Typed email',
  html: '<p>This is type-safe</p>',
};

const { data, error } = await truncus.emails.send(emailRequest);

Environment Configuration

Recommended environment setup:

# .env
TRUNCUS_API_KEY=tr_live_xxxx

# For development
TRUNCUS_API_KEY=tr_test_xxxx

Load with dotenv or your framework's env handling:

import 'dotenv/config';
import { Truncus } from '@truncus/node';

const truncus = new Truncus({
  apiKey: process.env.TRUNCUS_API_KEY!,
});

Framework Examples

Express.js

import express from 'express';
import { Truncus } from '@truncus/node';

const app = express();
const truncus = new Truncus({ apiKey: process.env.TRUNCUS_API_KEY! });

app.post('/send-welcome', async (req, res) => {
  const { email, name } = req.body;

  const { data, error } = await truncus.emails.send({
    from: 'welcome@yourdomain.com',
    to: email,
    subject: `Welcome, ${name}!`,
    html: `<h1>Hello ${name}</h1>`,
  });

  if (error) {
    return res.status(400).json({ error: error.message });
  }

  res.json({ messageId: data.id });
});

Next.js API Route

// app/api/contact/route.ts
import { NextResponse } from 'next/server';
import { Truncus } from '@truncus/node';

const truncus = new Truncus({ apiKey: process.env.TRUNCUS_API_KEY! });

export async function POST(request: Request) {
  const { email, message } = await request.json();

  const { error } = await truncus.emails.send({
    from: 'contact@yourdomain.com',
    to: 'team@yourdomain.com',
    replyTo: email,
    subject: 'New contact form submission',
    text: message,
  });

  if (error) {
    return NextResponse.json({ error: error.message }, { status: 400 });
  }

  return NextResponse.json({ success: true });
}

Next Steps

Send Email with Node.js: Complete Guide | Truncus Manual