npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@truncus/email

v0.2.0

Published

Node.js SDK for Truncus Email API

Readme

@truncus/email

Node.js SDK for Truncus — transactional email infrastructure built on AWS SES with deliverability built-in.

Installation

npm install @truncus/email
# or
pnpm add @truncus/email
# or
yarn add @truncus/email

Quick Start

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

const truncus = new Truncus({ apiKey: 'tr_live_...' });

const result = await truncus.sendEmail({
  to: '[email protected]',
  from: '[email protected]',
  subject: 'Welcome!',
  html: '<h1>Hello World</h1>',
});

console.log(result.id);     // Email ID
console.log(result.status); // 'sent'

Configuration

const truncus = new Truncus({
  apiKey: 'tr_live_...', // Required
  baseUrl: 'https://truncus.co', // Optional, defaults to production
  timeout: 30000,        // Optional, request timeout in ms (default 30s)
});

API Reference

Emails

sendEmail(options)

Send a transactional email.

const result = await truncus.sendEmail({
  // Required
  to: '[email protected]',
  from: '[email protected]', // Must match a verified domain
  subject: 'Welcome!',
  html: '<h1>Hello World</h1>',

  // Optional
  text: 'Hello World',              // Plain-text fallback
  cc: ['[email protected]'],
  bcc: ['[email protected]'],
  templateId: 'tmpl_...',           // Use a saved template instead of html
  variables: { name: 'John' },      // Template variables ({{name}})
  metadata: { userId: '123' },      // Custom metadata (stored, not sent)
  idempotencyKey: 'order-123',      // Prevent duplicate sends (auto-generated if omitted)
  tenantId: 'tenant_abc',           // Multi-tenant suppression isolation
  sendAt: '2026-03-10T09:00:00Z',  // Schedule for future delivery (ISO 8601, must be future)
  sandbox: true,                    // Skip SES — test without sending
  trackOpens: true,                 // 1×1 tracking pixel (default: true)
  trackClicks: true,                // Rewrite links through click proxy (default: true)
  attachments: [
    {
      filename: 'invoice.pdf',
      content: '<base64-encoded-content>',
      content_type: 'application/pdf',
    },
  ],
});

// result.status === 'sent'          — sent immediately
// result.status === 'scheduled'     — queued for sendAt time
// result.sendAt                     — ISO 8601 delivery time (scheduled emails)
// result.sandbox                    — true if sandbox mode was active

getEmail(emailId)

Retrieve details for a specific email, including open and click tracking stats.

const email = await truncus.getEmail('email_id');

console.log(email.status);    // 'delivered'
console.log(email.openCount); // 3 (total opens, including repeat opens)
console.log(email.openedAt);  // '2026-03-04T10:23:00Z' (first open)
console.log(email.clickCount);// 1

cancelEmail(emailId)

Cancel a scheduled email before it is dispatched. Only works on emails with status === 'scheduled'.

const result = await truncus.cancelEmail('email_id');
console.log(result.status); // 'cancelled'

Events

listEvents(options?)

List email events. Includes 'opened' and 'clicked' event types.

// All recent events
const { events } = await truncus.listEvents();

// Events for a specific email
const { events } = await truncus.listEvents({ emailId: 'email_id' });

// Filter by type
const { events } = await truncus.listEvents({ type: 'opened', limit: 50 });
const { events } = await truncus.listEvents({ type: 'clicked', limit: 50 });
const { events } = await truncus.listEvents({ type: 'delivered' });

Event types: queued | sent | delivered | bounce | complaint | failed | retry_scheduled | retry_attempted | opened | clicked

Domains

createDomain(options)

Add a sending domain. Returns DNS records to configure.

const domain = await truncus.createDomain({ domain: 'mail.yourdomain.com' });

// Configure these DNS records at your registrar:
console.log(domain.dnsRecords);
// [
//   { type: 'TXT', name: '_truncus.mail.yourdomain.com', value: 'truncus-verification=...' },
//   { type: 'TXT', name: 'mail.yourdomain.com', value: 'v=spf1 include:amazonses.com ~all' },
//   { type: 'CNAME', name: '...._domainkey.mail.yourdomain.com', value: '....dkim.amazonses.com' },
//   { type: 'TXT', name: '_dmarc.mail.yourdomain.com', value: 'v=DMARC1; p=quarantine; ...' },
// ]

verifyDomain(domainId)

Trigger DNS verification after configuring records.

const result = await truncus.verifyDomain('domain_id');
console.log(result.verified); // true when DNS is correct

listDomains()

List all domains with sending stats.

const { domains } = await truncus.listDomains();
domains.forEach((d) => {
  console.log(d.domain, d.status, d.sentToday);
});

Suppression

checkSuppression(email, tenantId?)

Check whether an address is on the suppression list before sending.

const status = await truncus.checkSuppression('[email protected]');
console.log(status.suppressed); // true / false
console.log(status.reason);     // 'bounce' | 'complaint' | null

For multi-tenant apps, scope the check to a specific tenant:

const status = await truncus.checkSuppression('[email protected]', 'tenant_abc');

Stats

getStats()

Aggregate sending stats for the account.

const stats = await truncus.getStats();
console.log(stats.sentToday);
console.log(stats.deliveryRate); // 0.98 (98%)
console.log(stats.bounceRate);   // 0.01 (1%)

Sandbox Mode

Test your integration without sending real emails:

const result = await truncus.sendEmail({
  to: '[email protected]',
  from: '[email protected]', // Domain validation skipped in sandbox
  subject: 'Test',
  html: '<p>Test</p>',
  sandbox: true,
});

console.log(result.sandbox); // true
console.log(result.status);  // 'sent' (simulated)

Sandbox skips SES entirely. No emails are delivered. Open/click tracking is also disabled.

Scheduled Sending

Schedule an email for future delivery. The email is queued immediately and dispatched at sendAt:

const result = await truncus.sendEmail({
  to: '[email protected]',
  from: '[email protected]',
  subject: 'Your weekly digest',
  html: '...',
  sendAt: '2026-03-10T09:00:00Z', // Must be a future datetime
});

console.log(result.status); // 'scheduled'
console.log(result.sendAt); // '2026-03-10T09:00:00.000Z'

// Cancel before dispatch
await truncus.cancelEmail(result.id);

Open & Click Tracking

Tracking is enabled by default. Truncus injects a 1×1 pixel for opens and rewrites links for click tracking. Unsubscribe links are never rewritten.

// Default — both opens and clicks tracked
const result = await truncus.sendEmail({ ..., html: '...' });

// Disable tracking
const result = await truncus.sendEmail({
  ...,
  html: '...',
  trackOpens: false,
  trackClicks: false,
});

// Check engagement after sending
const email = await truncus.getEmail(result.id);
console.log(email.openedAt);   // First open timestamp
console.log(email.openCount);  // Total opens (repeat opens counted)
console.log(email.clickCount); // Total link clicks

Events also fire for opens and clicks — query them with listEvents({ type: 'opened' }) or listEvents({ type: 'clicked' }).

Idempotency

Prevent duplicate sends by providing a stable idempotency key. If you retry with the same key, the original response is returned without sending again:

const result = await truncus.sendEmail({
  to: '[email protected]',
  from: '[email protected]',
  subject: 'Order Confirmation',
  html: '...',
  idempotencyKey: `order-${orderId}-confirmation`,
});

An idempotency key is auto-generated (UUID v4) when not provided.

Multi-tenant Apps

Isolate suppression lists per tenant so a bounce in one customer's account doesn't affect others:

const result = await truncus.sendEmail({
  to: '[email protected]',
  from: '[email protected]',
  subject: 'Welcome!',
  html: '...',
  tenantId: 'tenant_123',
});

Error Handling

import { TruncusError } from '@truncus/email';

try {
  await truncus.sendEmail({ ... });
} catch (error) {
  if (error instanceof TruncusError) {
    console.log(error.code);    // 'DOMAIN_NOT_VERIFIED'
    console.log(error.message); // 'Domain is not verified'
    console.log(error.status);  // 400
  }
}

Error Codes

| Code | Status | Description | |------|--------|-------------| | MISSING_API_KEY | 401 | Authorization header missing | | INVALID_API_KEY | 401 | API key is invalid or revoked | | SCOPE_REQUIRED | 403 | API key missing required scope | | INVALID_REQUEST | 400 | Request body validation failed | | DOMAIN_NOT_FOUND | 404 | Domain doesn't exist | | DOMAIN_NOT_VERIFIED | 400 | Domain pending DNS verification | | DOMAIN_PAUSED | 400 | Domain paused due to high bounce/complaint rate | | WARMUP_CAP_EXCEEDED | 429 | Daily sending limit reached | | ALL_RECIPIENTS_SUPPRESSED | 422 | All recipients are on suppression list | | PROVIDER_ERROR | 502 | AWS SES returned an error | | TIMEOUT | 408 | Request timed out | | NETWORK_ERROR | 0 | Network connectivity issue |

TypeScript

Full type definitions are included. Key types:

import type {
  SendEmailOptions,
  SendEmailResponse,
  EmailDetails,
  EmailStatus,
  EventType,
  EmailEvent,
  Domain,
  DomainStatus,
  SuppressionStatus,
  TruncusConfig,
} from '@truncus/email';

License

MIT