JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 8
  • Score
    100M100P100Q83455F
  • License MIT

Node.js SDK for the Send16 email platform

Package Exports

  • send16-mail

Readme

send16-mail — Email for developers

The official Node.js SDK for Send16 — transactional and marketing email that just works.

Zero runtime dependencies. ~22 KB on disk, no transitive packages, no supply-chain surface. Works in Node.js 18+, Bun, Deno, Cloudflare Workers, and any other runtime that ships fetch. TypeScript-first.

Install

npm install send16-mail

Get your API key

Create a free account and grab a key from Developers → API Keys. Free tier ships 1,000 emails/month.

Quick start

import { Send16 } from 'send16-mail';

const send16 = new Send16('sk_live_your_api_key_here');

const { data, error } = await send16.emails.send({
  from: 'Acme <hello@yourdomain.com>',
  to: ['user@gmail.com'],
  subject: 'Hello from Send16',
  html: '<p>Hello world</p>',
});

if (error) console.error('Failed:', error.message);
else console.log('Sent:', data.id);

Tasteful HTML in 5 lines — compose()

Don't want to write MJML or React Email? Pass a plain JS object and compose() returns a responsive, mobile-friendly HTML body plus a plain-text fallback. Pure function, runs anywhere, no API call needed for the render itself.

Welcome email

import { compose } from 'send16-mail';

const { html, text } = compose({
  product: { name: 'Acme', link: 'https://acme.com' },
  body: {
    name: 'John',
    intro: 'Welcome to Acme — your account is ready.',
    action: {
      instructions: 'Confirm your email to get started:',
      button: { text: 'Confirm email', link: 'https://acme.com/verify?t=abc' },
    },
    outro: 'Need help? Just reply to this email.',
  },
});

Password reset

const { html, text } = compose({
  product: { name: 'Acme' },
  body: {
    name: 'John',
    intro: 'You requested a password reset for your Acme account.',
    action: {
      instructions: 'Click the button below to choose a new password:',
      button: {
        text: 'Reset password',
        link: 'https://acme.com/reset?t=abc',
        color: '#dc2626',
      },
    },
    outro: 'If you did not request this, you can safely ignore the email.',
  },
});

Receipt

const { html, text } = compose({
  product: { name: 'Acme' },
  body: {
    name: 'John',
    intro: 'Thanks for your purchase! Here is your receipt.',
    table: {
      data: [
        { Item: 'Pro plan',      Quantity: '1', Price: '$29.00' },
        { Item: 'Extra seat',    Quantity: '2', Price: '$10.00' },
        { Item: 'Total',         Quantity: '',  Price: '$39.00' },
      ],
      columns: { customAlignment: { Price: 'right' } },
    },
    outro: 'Questions about your invoice? Reply and we will help.',
  },
});

Compose + send in one call

await send16.compose.send({
  from: 'Acme <hello@acme.com>',
  to: 'user@gmail.com',
  subject: 'Welcome!',
  product: { name: 'Acme' },
  body: { name: 'John', intro: 'Thanks for signing up.' },
});

Coming from mailgen?

send16-mail's compose() takes the same { product, body } shape — drop in your existing payload and you'll get HTML out the other side. The difference: we also send the email through a hosted, deliverability-tuned pipeline (DKIM/SPF/DMARC, dedicated IPs, bounce handling, opens/clicks, automations) instead of leaving you to wire up nodemailer + SES yourself.

// Roughly: replace this
const html = mailGenerator.generate({ body: { name, intro, action } });
await transporter.sendMail({ from, to, subject, html });

// …with this
await send16.compose.send({ from, to, subject, product, body: { name, intro, action } });

Why send16-mail

  • Zero dependencies — 22 KB SDK, no transitives, runs anywhere fetch exists
  • Edge-ready — Cloudflare Workers, Vercel Edge, Deno Deploy out of the box
  • Resend-compatible API — easy migration from Resend / SendGrid / Postmark / Mailgun
  • Self-hosted option — bring your own server if you want full control
  • Transactional + marketing — one platform, one SDK
  • Free tier — 1,000 emails/month, no credit card

Configuration

const send16 = new Send16('sk_live_your_key', {
  baseUrl: 'https://api.send16.com', // default; override for self-hosted
  timeout: 30_000,                    // ms; default 30s
});

Emails

Send

const { data, error } = await send16.emails.send({
  from: 'Acme <hello@acme.com>',
  to: ['user@gmail.com'],
  subject: 'Hello',
  html: '<p>Hello world</p>',
});

All options

await send16.emails.send({
  from: 'Acme <hello@acme.com>',
  to: ['user@gmail.com'],
  cc: ['cc@example.com'],
  bcc: ['bcc@example.com'],
  replyTo: 'support@acme.com',
  subject: 'Invoice #1234',
  html: '<p>Your invoice is attached.</p>',
  text: 'Your invoice is attached.',
  headers: { 'X-Custom-Header': 'value' },
  attachments: [
    { filename: 'invoice.pdf', content: '<base64>', contentType: 'application/pdf' },
  ],
  tags: [{ name: 'category', value: 'invoices' }],
  scheduledAt: '2026-04-01T09:00:00Z',
});

Batch (up to 100)

await send16.emails.batch([
  { from: 'Acme <hi@acme.com>', to: ['a@x.com'], subject: 'Hi A', html: '<p>Hi!</p>' },
  { from: 'Acme <hi@acme.com>', to: ['b@x.com'], subject: 'Hi B', html: '<p>Hi!</p>' },
]);

Contacts

await send16.contacts.create({ email: 'user@test.com', firstName: 'John' });
await send16.contacts.list({ page: 1, limit: 50 });
await send16.contacts.update('id', { firstName: 'Jane' });
await send16.contacts.delete('id');

Domains

await send16.domains.list();
await send16.domains.verify('domain-id');

Render (compile dashboard email content → HTML)

const { data } = await send16.render.run({
  content: emailContent, // EmailContent JSON from the Send16 editor
  variables: { firstName: 'John' },
});
console.log(data.html); // exact HTML the API will send

Events (trigger automations)

await send16.events.send({
  name: 'signup_completed',
  contact: 'user@gmail.com',
  payload: { plan: 'pro' },
});

Error handling

The SDK never throws. Every method returns { data, error }:

const { data, error } = await send16.emails.send({ /* ... */ });
if (error) {
  console.error(error.code);    // "HTTP_422" | "TIMEOUT" | "NETWORK_ERROR" | ...
  console.error(error.message);
  return;
}
console.log(data.id); // non-null when error is null

TypeScript

Full types are bundled. Common imports:

import type {
  SendEmailPayload,
  SendEmailResponse,
  Contact,
  Domain,
  ComposeInput,
  ComposeResult,
} from 'send16-mail';

Companion packages

  • send16-clisend16 command-line tool: send local .tsx/.mjml/.html files, manage domains/contacts, fire events.
  • send16-editor — embeddable React block editor your users can compose emails in directly inside your app.

License

MIT