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

@jconet-ltd/mailchannels-client

v1.1.1

Published

Lightweight TypeScript wrapper for the MailChannels Email API.

Downloads

96

Readme

@jconet-ltd/mailchannels-client

Builds Coverage

TypeScript-first wrapper around the MailChannels Email API with runtime validation, DKIM enforcement, and ergonomic helpers. The client targets Node.js 18+ and reuses the built-in Fetch API, so there are no production dependencies.

ℹ️ Before sending email you must provision an SMTP password, generate an API key with the api scope, and configure Domain Lockdown records as documented by MailChannels.1

Table of contents

Installation

# pnpm
pnpm add @jconet-ltd/mailchannels-client

# npm
npm install @jconet-ltd/mailchannels-client

# Yarn
yarn add @jconet-ltd/mailchannels-client

# Bun
bun add @jconet-ltd/mailchannels-client

Quick start

import { MailChannelsClient } from "@jconet-ltd/mailchannels-client";

const client = new MailChannelsClient({
  apiKey: process.env.MAILCHANNELS_API_KEY ?? "",
  dkim: {
    domain: "example.com",
    selector: "mcdkim",
    privateKey: process.env.MAILCHANNELS_DKIM_PRIVATE_KEY ?? "",
  },
});

await client.sendEmail({
  personalizations: [
    {
      to: [{ email: "[email protected]", name: "Sakura Tanaka" }],
    },
  ],
  from: { email: "[email protected]", name: "Priya Patel" },
  subject: "Testing Email API",
  content: [
    { type: "text/plain", value: "Hi Sakura. This is just a test from Priya." },
    {
      type: "text/html",
      value: "<p>Hi Sakura.<br>This is just a test from Priya.</p>",
    },
  ],
});

The client injects the DKIM defaults into both the request body and every personalization, ensuring compliance with MailChannels' DKIM requirements even when you do not set them manually.

Under the hood the client issues a POST request to https://api.mailchannels.net/tx/v1/send with your API key in the X-Api-Key header, exactly as described in the MailChannels sending guide.2

Features

  • Required DKIM configuration enforced at construction time to keep every request compliant.3
  • Strong TypeScript definitions that mirror the MailChannels /send payload.5
  • Runtime validation of key fields (personalizations, content, DKIM) before the network hop.
  • Optional dry-run support (?dry-run=true) so you can validate payloads without delivering mail.6
  • Detailed error metadata surfaced via MailChannelsError, including request identifiers, retry hints, headers, and the original payload.
  • Attachment helper validation around MIME type, filename, and Base64 encoding.7
  • Built-in Fetch integration with an escape hatch for custom implementations (tests, polyfills).

MailChannels setup guide

  1. Create an account. Sign up for MailChannels, verify your email address, and add valid billing details as prompted.1

  2. Complete the authentication prerequisites. From the console create an SMTP password, generate an API key with the api scope, and publish Domain Lockdown (_mailchannels) TXT records for every sending domain.2

  3. Provision DKIM. MailChannels requires DKIM signatures for modern deliverability. You can:

    • Generate a private key, derive the public key, and publish it at selector._domainkey.yourdomain. Sample OpenSSL commands:3

      openssl genrsa 2048 | tee priv_key.pem \
        | openssl rsa -outform der \
        | openssl base64 -A > priv_key.txt
      
      echo -n "v=DKIM1;p=" > pub_key_record.txt
      openssl rsa -in priv_key.pem -pubout -outform der \
        | openssl base64 -A >> pub_key_record.txt

      Publish the contents of pub_key_record.txt as a TXT record at <selector>._domainkey.<yourdomain>.

    • Or call the MailChannels DKIM APIs (POST /tx/v1/domains/{domain}/dkim-keys, etc.) to generate and activate key pairs directly, then publish the returned DNS record.3

  4. Record your defaults. Capture the following details for the domain you will sign with:

    • dkim_domain – typically the same domain as your From address for DMARC alignment.
    • dkim_selector – the label you used in DNS (for example mcdkim).
    • dkim_private_key – the Base64-encoded private key (contents of priv_key.txt if you used the OpenSSL recipe above).

Once the DNS changes propagate you are ready to send signed traffic through the /send endpoint.4

Per-recipient overrides

You can still customise DKIM (and other headers) per recipient. Values defined inside a personalization override the client defaults for that specific message.

import { MailChannelsClient } from "@jconet-ltd/mailchannels-client";
import type { SendEmailRequest } from "@jconet-ltd/mailchannels-client";

const client = new MailChannelsClient({
  apiKey: "YOUR-API-KEY",
  dkim: {
    domain: "example.com",
    selector: "mcdkim",
    privateKey: "BASE64_PRIVATE_KEY",
  },
});

const message: SendEmailRequest = {
  personalizations: [
    {
      to: [{ email: "[email protected]" }],
      subject: "BANANAS ARE ON SALE",
      dynamic_template_data: { discountCode: "BANANA-BOAT" },
    },
    {
      to: [{ email: "[email protected]" }],
      subject: "Exclusive VIP Pricing",
      dkim_selector: "vipselector",
      dkim_private_key: "BASE64_VIP_KEY",
    },
  ],
  from: { email: "[email protected]", name: "Example News" },
  template_id: "spring-sale",
  content: [
    {
      type: "text/plain",
      value: "Plain-text fallback for clients that do not render HTML.",
    },
    {
      type: "text/html",
      value:
        "<html><body><p>Check the sale in your personalized template.</p></body></html>",
    },
  ],
  metadata: { campaign: "spring-2025" },
};

await client.sendEmail(message, { dryRun: true });

Attachments

Attachments must be Base64 encoded and accompanied by a MIME type plus filename. The client checks these fields before sending.

import { MailChannelsClient } from "@jconet-ltd/mailchannels-client";
import { promises as fs } from "node:fs";

const client = new MailChannelsClient({
  apiKey: "YOUR-API-KEY",
  dkim: {
    domain: "example.com",
    selector: "mcdkim",
    privateKey: "BASE64_PRIVATE_KEY",
  },
});

const logoPngBase64 = Buffer.from(
  await fs.readFile("./assets/logo.png")
).toString("base64");

await client.sendEmail({
  personalizations: [{ to: [{ email: "[email protected]" }] }],
  from: { email: "[email protected]" },
  subject: "Email with Attachment",
  content: [{ type: "text/plain", value: "Please see the attached image." }],
  attachments: [
    {
      type: "image/png",
      filename: "logo.png",
      content: logoPngBase64,
    },
  ],
});

Error handling

API failures throw a MailChannelsError with rich diagnostics so you can log or retry intelligently. In addition to the message and status code, the error exposes the HTTP status text, response headers, any structured body, the upstream request identifier, and a parsed retryAfterSeconds hint when the service returns Retry-After.

import { MailChannelsError } from "@jconet-ltd/mailchannels-client";

try {
  await client.sendEmail(payload);
} catch (error) {
  if (error instanceof MailChannelsError) {
    console.error(
      "MailChannels request failed",
      error.status,
      error.statusText,
      error.requestId
    );

    if (error.retryAfterSeconds) {
      console.info("Safe to retry in", error.retryAfterSeconds, "seconds");
    }

    console.debug("Response headers", error.headers);
    console.debug("Original payload", error.details);
  }
  throw error;
}

Testing

npm install
npm run typecheck
npm run build

npm run build emits ESM output plus .d.ts bundles into dist/ ready for publishing.

API surface

new MailChannelsClient(options)

  • apiKey – MailChannels API credential with the api scope.2
  • dkim – required defaults { domain, selector, privateKey }; applied automatically to every request and personalization.3
  • baseUrl – override the API endpoint (defaults to https://api.mailchannels.net/tx/v1/).
  • fetchImplementation – provide an alternative Fetch-compatible function if needed.
  • defaultHeaders – headers merged into every outbound request.

sendEmail(payload, options?)

  • Accepts a strongly typed payload matching the MailChannels /send schema.5
  • Ensures DKIM, recipients, and content blocks are valid before calling the API.
  • options.dryRun toggles the dry-run query to request synchronous validation.6
  • options.signal lets you cancel in-flight requests with an AbortSignal.
  • options.idempotencyKey sets the Idempotency-Key header for safe retries.

Errors

Non-success responses raise MailChannelsError, exposing the HTTP status, status text, request identifier, retry hints, headers, and the parsed or raw response body. Advanced callers can construct the error manually with MailChannelsErrorOptions when wrapping lower-level utilities.

Footnotes

  1. MailChannels account creation
  2. Authentication prerequisites and Domain Lockdown
  3. DKIM setup and field requirements
  4. Sending emails with the /send endpoint
  5. Understanding the /send payload structure
  6. Dry-run behaviour in the API reference
  7. Attachment requirements and limitations