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

kannon.js

v1.0.2

Published

Kannon node client libreary

Readme

Kannon.js

CI

The official Node.js client library for Kannon Email Sender.

Installation

npm install kannon.js

Quick Start

import { KannonCli } from 'kannon.js';

const kannon = new KannonCli(
  'your-domain.com',
  'your-api-key',
  {
    email: '[email protected]', // this should match the domain host
    alias: 'Kannon',
  },
  {
    endpoint: 'https://api.kannon.dev',
  },
);

// Send a simple HTML email
await kannon.sendHtml(
  ['[email protected]'],
  'Welcome to Kannon!',
  '<h1>Hello!</h1><p>Welcome to our platform.</p>',
);

MailSender - Simple Email API

For straightforward email sending without templating, use MailSender. It provides a traditional mail client API with To, CC, and BCC support.

Basic Usage

import { KannonCli, MailSender } from 'kannon.js';

const kannon = new KannonCli(
  'your-domain.com',
  'your-api-key',
  { email: '[email protected]', alias: 'Kannon' },
  { endpoint: 'https://api.kannon.dev' },
);

const mailSender = new MailSender(kannon);

await mailSender.send({
  to: '[email protected]',
  subject: 'Hello',
  content: '<p>Hello, World!</p>',
});

With CC and BCC

await mailSender.send({
  to: ['[email protected]', '[email protected]'],
  cc: '[email protected]',
  bcc: '[email protected]',
  subject: 'Project Update',
  content: '<h1>Status Report</h1><p>All systems operational.</p>',
});

With Attachments

import { readFileSync } from 'fs';

await mailSender.send({
  to: '[email protected]',
  subject: 'Monthly Report',
  content: '<h1>Report</h1><p>See attachment.</p>',
  attachments: [
    {
      filename: 'report.pdf',
      content: readFileSync('./report.pdf'),
    },
  ],
});

Scheduled Delivery

const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);

await mailSender.send({
  to: '[email protected]',
  subject: 'Scheduled Reminder',
  content: '<p>This email was scheduled.</p>',
  scheduledTime: tomorrow,
});

MailSender API Reference

SendParams

| Field | Type | Required | Description | |-------|------|----------|-------------| | to | string \| string[] | Yes | Primary recipient(s) | | subject | string | Yes | Email subject line | | content | string | Yes | HTML email body | | cc | string \| string[] | No | Carbon copy recipients (visible to all) | | bcc | string \| string[] | No | Blind carbon copy recipients (hidden) | | attachments | Attachment[] | No | File attachments | | scheduledTime | Date | No | Schedule for future delivery |

SendResult

| Field | Type | Description | |-------|------|-------------| | messageId | string | Unique identifier for the sent message | | scheduledTime | Date \| undefined | Scheduled delivery time (if applicable) |


Usage Examples (KannonCli)

Basic Email Sending

Simple HTML Email

const html = `
  <h1>Welcome to Kannon!</h1>
  <p>Thank you for signing up.</p>
  <a href="https://kannon.dev">Visit our website</a>
`;

await kannon.sendHtml(['[email protected]'], 'Welcome to Kannon', html);

Multiple Recipients

const recipients = ['[email protected]', '[email protected]', '[email protected]'];

await kannon.sendHtml(recipients, 'Important Update', '<h1>System Update</h1><p>We have important news for you.</p>');

With Attachments

import { readFileSync } from 'fs';

const pdfBuffer = readFileSync('./document.pdf');

await kannon.sendHtml(
  ['[email protected]'],
  'Your Invoice',
  '<h1>Invoice Attached</h1><p>Please find your invoice attached.</p>',
  {
    attachments: [
      {
        filename: 'invoice.pdf',
        content: pdfBuffer,
      },
      {
        filename: 'terms.txt',
        content: Buffer.from('Terms and conditions...'),
      },
    ],
  },
);

Template Emails

Using Template IDs

await kannon.sendTemplate(['[email protected]'], 'Your Order Confirmation', 'order-confirmation-template');

Templates with Attachments

await kannon.sendTemplate(['[email protected]'], 'Monthly Report', 'monthly-report-template', {
  attachments: [
    {
      filename: 'report.pdf',
      content: reportBuffer,
    },
  ],
});

Personalized Emails

Individual Fields

const html = `
  <h1>Hello {{name}}!</h1>
  <p>Your account balance is: {{balance}}</p>
  <p>Last login: {{lastLogin}}</p>
`;

await kannon.sendHtml(
  [
    {
      email: '[email protected]',
      fields: {
        name: 'John',
        balance: '$1,250',
        lastLogin: '2024-01-15',
      },
    },
    {
      email: '[email protected]',
      fields: {
        name: 'Jane',
        balance: '$890',
        lastLogin: '2024-01-14',
      },
    },
  ],
  'Account Update',
  html,
);

Mixed Recipient Types

const recipients = [
  '[email protected]', // String format
  {
    email: '[email protected]',
    fields: { name: 'Alice', role: 'Admin' },
  }, // Object format
  {
    email: '[email protected]',
    fields: { name: 'Bob', role: 'User' },
  },
];

const html = `
  <h1>Hello {{name || 'there'}}!</h1>
  <p>Your role: {{role || 'Guest'}}</p>
`;

await kannon.sendHtml(recipients, 'Welcome', html);

Global Fields

Shared Content for All Recipients

const html = `
  <h1>Hello {{name}}!</h1>
  <p>This is a message from {{company}}.</p>
  <p>Current date: {{currentDate}}</p>
  <p>Support email: {{supportEmail}}</p>
`;

await kannon.sendHtml(
  [
    { email: '[email protected]', fields: { name: 'John' } },
    { email: '[email protected]', fields: { name: 'Jane' } },
  ],
  'Company Update',
  html,
  {
    globalFields: {
      company: 'Kannon Corp',
      currentDate: new Date().toLocaleDateString(),
      supportEmail: '[email protected]',
    },
  },
);

Scheduled Emails

Future Delivery

const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);

await kannon.sendHtml(
  ['[email protected]'],
  "Tomorrow's Reminder",
  "<h1>Don't forget!</h1><p>Your meeting is tomorrow.</p>",
  {
    scheduledTime: tomorrow,
  },
);

Specific Date and Time

const scheduledTime = new Date('2024-02-01T10:00:00Z');

await kannon.sendTemplate(['[email protected]'], 'Weekly Newsletter', 'newsletter-template', {
  scheduledTime,
  globalFields: {
    weekNumber: '5',
    year: '2024',
  },
});

Email Headers (To/CC)

Adding CC Recipients

await kannon.sendHtml(
  ['[email protected]'],
  'Project Update',
  '<h1>Project Status</h1><p>Here is the latest update.</p>',
  {
    headers: {
      cc: ['[email protected]', '[email protected]'],
    },
  },
);

Custom To Header

await kannon.sendHtml(
  ['[email protected]'],
  'Meeting Invitation',
  '<h1>You are invited!</h1><p>Please join us for the quarterly review.</p>',
  {
    headers: {
      to: ['[email protected]'],
      cc: ['[email protected]'],
    },
  },
);

Advanced Configuration

Custom Domain Setup

const kannon = new KannonCli(
  'mycompany.com',
  'your-api-key',
  {
    email: '[email protected]',
    alias: 'My Company',
  },
  {
    endpoint: 'https://api.mycompany.com',
  },
);

Development Environment

const kannon = new KannonCli(
  'dev.example.com',
  'dev-api-key',
  {
    email: '[email protected]',
    alias: 'Dev Environment',
  },
  {
    endpoint: 'http://localhost:8080', // HTTP for local development
  },
);

Production with Custom Port

const kannon = new KannonCli(
  'production.com',
  'prod-api-key',
  {
    email: '[email protected]',
    alias: 'Production System',
  },
  {
    endpoint: 'https://api.production.com:8443', // Custom HTTPS port
  },
);

API Reference

KannonCli Constructor

new KannonCli(
  domain: string,
  apiKey: string,
  sender: KannonSender,
  config: KannonConfig
)

Parameters:

  • domain: Your Kannon domain
  • apiKey: Your Kannon API key
  • sender: Sender configuration
    • email: Sender email address
    • alias: Sender display name
  • config: Client configuration
    • endpoint: API endpoint (must include protocol)

Methods

sendHtml(recipients, subject, html, options?)

Sends an HTML email.

Parameters:

  • recipients: Array of recipients (strings or objects with fields)
  • subject: Email subject line
  • html: HTML content of the email
  • options: Optional configuration

sendTemplate(recipients, subject, templateId, options?)

Sends a template email.

Parameters:

  • recipients: Array of recipients (strings or objects with fields)
  • subject: Email subject line
  • templateId: ID of the template to use
  • options: Optional configuration

Options

type SendOptions = {
  scheduledTime?: Date; // When to send the email
  globalFields?: Record<string, string>; // Fields shared by all recipients
  attachments?: {
    // File attachments
    filename: string;
    content: Buffer;
  }[];
  headers?: {
    // Email headers
    to?: string[]; // Additional To header addresses
    cc?: string[]; // CC header addresses
  };
};

Types

type Recipient =
  | string // Simple email address
  | {
      // Email with personalized fields
      email: string;
      fields?: Record<string, string>;
    };

type KannonSender = {
  email: string;
  alias: string;
};

type KannonConfig = {
  endpoint: string;
};

Error Handling

try {
  await kannon.sendHtml(['[email protected]'], 'Test Email', '<h1>Hello</h1>');
  console.log('Email sent successfully!');
} catch (error) {
  console.error('Failed to send email:', error.message);

  if (error.code === 'AUTHENTICATION_FAILED') {
    console.error('Check your API key and domain');
  } else if (error.code === 'INVALID_RECIPIENT') {
    console.error('Check recipient email addresses');
  }
}

🚨 Breaking Changes in v1.0.0

This version introduces breaking changes due to the migration from ts-proto to connect-es:

Endpoint Configuration Changes

Before (v1.0.0):

const kannon = new KannonCli(
  'your-domain.com',
  'your-api-key',
  { email: '[email protected]', alias: 'Kannon' },
  { host: 'api.kannon.dev:443' }, // ❌ Old format
);

After (v1.0.0):

const kannon = new KannonCli(
  'your-domain.com',
  'your-api-key',
  { email: '[email protected]', alias: 'Kannon' },
  { endpoint: 'https://api.kannon.dev' }, // ✅ New format with protocol
);

Key Changes:

  • Protocol required: You must now specify the protocol (https:// or http://)
  • Port optional: Standard ports (443 for HTTPS, 80 for HTTP) are automatically used
  • TLS handling: The skipTLS option is no longer supported
  • Parameter renamed: host parameter is now endpoint for clarity

Migration Examples:

| Old Format (host) | New Format (endpoint) | | -------------------- | ------------------------ | | api.kannon.dev:443 | https://api.kannon.dev | | api.kannon.dev:80 | http://api.kannon.dev | | localhost:8080 | http://localhost:8080 | | localhost:8443 | https://localhost:8443 |

Migration Guide

If you're upgrading from v1.0.0:

  1. Update endpoint configuration to include protocol
  2. Rename host to endpoint in your configuration
  3. Remove port numbers if using standard ports (443/80)
  4. Test your integration to ensure compatibility

Example migration:

// Before
const kannon = new KannonCli('domain', 'key', sender, {
  host: 'api.kannon.dev:443',
});

// After
const kannon = new KannonCli('domain', 'key', sender, {
  endpoint: 'https://api.kannon.dev',
});

The host parameter is removed. Please use endpoint instead:

const kannon = new KannonCli('domain', 'key', sender, {
  endpoint: 'https://api.kannon.dev',
});

License

ISC