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

@kumix/email

v0.1.3

Published

Email templates and sending utilities for SaaS applications.

Readme

@kumix/email

Version License: MIT

A flexible email package for SaaS applications. Supports Resend and Nodemailer/SMTP, React Email templates, and all JavaScript runtimes.

Installation

# Node.js / Bun
bun add @kumix/email resend
# or
npm install @kumix/email resend

# Optional: install nodemailer for SMTP (Node.js / Bun / Deno only)
bun add nodemailer

Configuration by Runtime

Node.js / Bun

Set environment variables and call createEmail() — it auto-detects your provider.

# .env
KUMIX_EMAIL_RESEND_API_KEY=re_xxxx
KUMIX_EMAIL_FROM_NAME=My App
[email protected]
[email protected]
import { createEmail } from "@kumix/email";

// Reads process.env automatically
const email = createEmail();

await email.sendEmail({
  to: "[email protected]",
  subject: "Welcome!",
  html: "<h1>Hello World</h1>",
});

Bun works identically to Node.js — process.env is natively supported.

Cloudflare Workers

Pass ctx.env as the second argument. Resend only (Nodemailer is Node-only).

# wrangler.toml
[vars]
KUMIX_EMAIL_RESEND_API_KEY = "re_xxxx"
KUMIX_EMAIL_FROM_NAME = "My App"
KUMIX_EMAIL_FROM_EMAIL = "[email protected]"
// worker.ts
import { createEmail, type EnvRecord } from "@kumix/email";

interface Env extends EnvRecord {
  KUMIX_EMAIL_RESEND_API_KEY: string;
  KUMIX_EMAIL_FROM_NAME: string;
  KUMIX_EMAIL_FROM_EMAIL: string;
}

export default {
  async fetch(req: Request, env: Env) {
    const email = createEmail(undefined, env);

    await email.sendEmail({
      to: "[email protected]",
      subject: "Hello from Workers!",
      html: "<p>Sent from Cloudflare Workers</p>",
    });

    return new Response("Email sent");
  },
};

With React templates in Workers:

import { createEmail, type EnvRecord } from "@kumix/email";

interface WelcomeProps {
  userName: string;
  loginUrl: string;
}

const WelcomeEmail: React.FC<WelcomeProps> = ({ userName, loginUrl }) => (
  <div>
    <h1>Welcome, {userName}!</h1>
    <a href={loginUrl}>Login here</a>
  </div>
);

export default {
  async fetch(req: Request, env: Env) {
    const email = createEmail(undefined, env);

    await email.sendTemplate(
      WelcomeEmail,
      { userName: "Alice", loginUrl: "https://app.example.com" },
      { to: "[email protected]", subject: "Welcome!" },
    );

    return new Response("Template email sent");
  },
};

Deno

Deno supports process.env natively (requires --allow-env). You can also pass env explicitly.

# .env
KUMIX_EMAIL_RESEND_API_KEY=re_xxxx
KUMIX_EMAIL_FROM_NAME=My App
[email protected]
// main.ts
import { createEmail } from "@kumix/email";

// Option A: let the package read process.env (Deno supports it)
const email = createEmail();

// Option B: pass env explicitly
const email = createEmail(undefined, Deno.env.toObject());

await email.sendEmail({
  to: "[email protected]",
  subject: "Hello from Deno!",
  html: "<h1>Deno works</h1>",
});
deno run --allow-env --allow-net main.ts

With Nodemailer (SMTP) in Deno:

import { createNodemailer } from "@kumix/email";

const email = createNodemailer({
  from: { name: "My App", email: "[email protected]" },
  smtp: {
    host: "smtp.gmail.com",
    port: 587,
    secure: false,
    auth: { user: "[email protected]", pass: "app-password" },
  },
});

await email.sendEmail({
  to: "[email protected]",
  subject: "SMTP from Deno",
  html: "<p>Sent via SMTP</p>",
});

nodemailer is loaded via a dynamic import() and is a Node-oriented package. In Deno, install it through an npm: specifier (deno run --allow-env --allow-net ... with npm:nodemailer@^9 resolvable). Bun and Node.js resolve it from node_modules automatically.

Browser

Use manual config — no env vars. Resend only, since Nodemailer requires Node.js APIs.

import { createResend } from "@kumix/email";

const email = createResend({
  apiKey: "re_xxxx",
  from: { name: "My App", email: "[email protected]" },
});

await email.sendEmail({
  to: "[email protected]",
  subject: "Hello from the browser!",
  html: "<p>Sent from client-side JavaScript</p>",
});

Security note: Exposing your Resend API key in browser code is insecure. Use this pattern behind an authenticated route in an admin dashboard, or proxy through your backend.

Manual Configuration (any runtime)

Skip env vars entirely — pass your config object directly. Works in every runtime.

import { createResend, createNodemailer } from "@kumix/email";

// Resend — works everywhere
const resend = createResend({
  apiKey: "re_xxxx",
  from: { name: "My App", email: "[email protected]" },
});

// Nodemailer — Node.js / Bun / Deno only
const nodemailer = createNodemailer({
  from: { name: "My App", email: "[email protected]" },
  smtp: {
    host: "smtp.gmail.com",
    port: 587,
    secure: false,
    auth: { user: "[email protected]", pass: "app-password" },
  },
});

EnvRecord Pattern

All config and factory functions accept an optional env parameter of type Record<string, string | undefined>. On Node.js / Bun it defaults to process.env. On other runtimes, pass your environment explicitly:

import {
  createEmail,
  createResend,
  hasEmailConfig,
  loadEmailConfig,
  validateEmailEnvVars,
  type EnvRecord,
} from "@kumix/email";

// All accept env as the last argument:
const email = createEmail(undefined, myEnv);
const config = loadEmailConfig(myEnv);
const ready = hasEmailConfig(myEnv);
const result = validateEmailEnvVars(myEnv);

Sending Emails

HTML Emails

await email.sendEmail({
  to: "[email protected]",
  subject: "Hello!",
  html: "<p>This is an HTML email</p>",
  text: "This is the plain text version",
});

React Templates

import { EmailTemplate } from "./templates/EmailTemplate";

await email.sendTemplate(
  EmailTemplate,
  { userName: "John", resetLink: "https://..." },
  { to: "[email protected]", subject: "Password Reset" },
);

Advanced Options

await email.sendEmail({
  to: ["[email protected]", "[email protected]"],
  cc: "[email protected]",
  bcc: "[email protected]",
  subject: "Important Update",
  html: "<h1>Update</h1>",
  attachments: [
    {
      filename: "document.pdf",
      content: pdfBuffer,
      contentType: "application/pdf",
    },
  ],
  headers: { "X-Custom-Header": "value" },
  tags: { category: "notification" },
});

Priority & Scheduled Delivery

Both providers support a numeric priority (1 = highest … 5 = lowest). It is forwarded to Nodemailer as the priority field plus an X-Priority header, and to Resend as an X-Priority header.

await email.sendEmail({
  to: "[email protected]",
  subject: "Incident",
  html: "<p>High priority</p>",
  priority: 1, // 1..5
});

Resend also supports deferred delivery via scheduledAt (an ISO 8601 timestamp). It is forwarded as Resend's scheduled_at field. Nodemailer ignores this option.

await email.sendEmail({
  to: "[email protected]",
  subject: "Scheduled",
  html: "<p>Sent later</p>",
  scheduledAt: new Date("2030-01-01T09:00:00Z"),
});

Runtime Compatibility

| Feature | Node.js | Bun | CF Workers | Deno | Browser | | ------------------- | ------- | --- | ---------- | ---- | ------- | | Resend provider | Yes | Yes | Yes | Yes | Yes | | Nodemailer/SMTP | Yes | Yes | No | Yes | No | | createEmail() | Yes | Yes | Yes* | Yes | No | | Manual config | Yes | Yes | Yes | Yes | Yes | | React templates | Yes | Yes | Yes | Yes | Yes | | Env auto-detection | Yes | Yes | No† | Yes | No | | helpers subpath | Yes | Yes | Yes | Yes | Yes | | components export | Yes | Yes | Yes | Yes | Yes |

* Pass env as second argument: createEmail(undefined, ctx.env). † Pass env explicitly via EnvRecord pattern.

API Reference

Factory Functions

  • createEmail(config?, env?) — Create from config or env, auto-detects provider
  • createResend(config?, env?) — Create Resend email service
  • createNodemailer(config?, env?) — Create Nodemailer email service
  • isEmailConfigured(env?) — Check if email is configured via env
  • getConfiguredProvider(env?) — Get the detected provider from env

EmailService Methods

  • sendEmail(options) — Send HTML/text email
  • sendTemplate(component, props, options) — Send React template email
  • getConfig() — Get current configuration
  • updateConfig(config) — Update configuration at runtime
  • validateConfig() — Validate current configuration

Config Helpers

  • loadEmailConfig(env?) — Auto-detect and load config from env
  • loadResendConfig(env?) — Load Resend config from env
  • loadNodemailerConfig(env?) — Load SMTP config from env
  • validateEmailEnvVars(env?) — Validate any configured provider
  • validateResendEnvVars(env?) — Validate Resend env vars
  • validateNodemailerEnvVars(env?) — Validate SMTP env vars
  • getEmailEnvVars(env?) — Get env vars with secrets masked
  • hasEmailConfig(env?) — Check if any provider is configured

Helpers (@kumix/email/helpers)

  • renderEmailTemplate(Component, props) — Render React component to HTML string
  • htmlToText(html) — Convert HTML to plain text
  • isValidEmail(email) — Validate common email format (permissive sanity check, not full RFC 5322)
  • validateEmails(emails) — Validate single or multiple emails
  • filterValidEmails(emails) — Filter invalid emails from a list
  • formatEmailAddress(name, email) — Format as "Name" <email> (display name is quoted/escaped per RFC 5322; CR/LF stripped to prevent header injection)
  • extractEmail(formatted) — Extract email from formatted address
  • extractDisplayName(formatted) — Extract display name from formatted address
  • sanitizeHtml(html) — Coarse cleanup that strips <script>/<style>/<iframe>/<object>/<embed>/<form>/<svg> blocks, on* event handlers, and javascript: URLs. ⚠️ NOT a security sanitizer — for untrusted input use a purpose-built sanitizer (e.g. DOMPurify)
  • truncateText(text, maxLength, ellipsis?) — Truncate with ellipsis
  • generatePreviewText(html, maxLength?) — Generate email preview text
  • generateUnsubscribeLink(baseUrl, email, token?) — Create unsubscribe URL
  • generateTrackingPixel(baseUrl, emailId, recipientId) — Create tracking pixel URL
  • addUtmParams(url, params) — Add UTM tracking parameters
  • parseEmailList(str) — Parse comma/semicolon-separated emails
  • deduplicateEmails(emails) — Deduplicate (case-insensitive)
  • chunkEmails(emails, chunkSize?) — Split into batches (default 100)
  • getMimeType(filename) — Get MIME type from extension
  • formatFileSize(bytes, decimals?) — Format file size in human-readable form

Types

import type {
  // Config shapes
  EmailConfig,
  ResendConfig,
  NodemailerConfig,
  BaseEmailConfig,
  EmailProvider,
  EnvRecord,
  // Sending
  SendEmailOptions,
  EmailAttachment,
  EmailResult,
  EmailValidationResult,
  IEmailProvider,
  ConfigValidationResult,
  EmailTemplateData,
} from "@kumix/email";

Environment Variables

| Variable | Provider | Required | | ---------------------------- | ---------- | -------- | | KUMIX_EMAIL_RESEND_API_KEY | Resend | Yes | | KUMIX_EMAIL_FROM_NAME | All | Yes | | KUMIX_EMAIL_FROM_EMAIL | All | Yes | | KUMIX_EMAIL_REPLY_TO | All | No | | KUMIX_EMAIL_SMTP_HOST | Nodemailer | Yes | | KUMIX_EMAIL_SMTP_PORT | Nodemailer | Yes | | KUMIX_EMAIL_SMTP_SECURE | Nodemailer | No |

KUMIX_EMAIL_SMTP_SECURE enables TLS when set to true, 1, or yes (case-insensitive); any other value (or unset) leaves the connection unsecured. Defaults to off — set it explicitly for port 465 (implicit TLS). | KUMIX_EMAIL_SMTP_USER | Nodemailer | Yes | | KUMIX_EMAIL_SMTP_PASS | Nodemailer | Yes |

Legacy env vars (RESEND_API_KEY, SMTP_HOST, etc.) are also supported for backward compatibility.

Links

License

MIT © Kumix Labs