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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@geekmidas/emailkit

v0.0.7

Published

Type-safe email client with SMTP support and React templates

Downloads

301

Readme

@geekmidas/emailkit

Type-safe email client with SMTP support and React templates.

Features

  • Type-Safe Templates: Templates are provided at construction time with full TypeScript inference for both template names and their corresponding props
  • SMTP Support: Works with any SMTP server via nodemailer configuration
  • React Templates: Uses react-dom/server to render React components to HTML

Installation

pnpm add @geekmidas/emailkit

Quick Start

import { createEmailClient } from '@geekmidas/emailkit';

// Define your templates with props
const WelcomeEmail = ({ name, confirmationUrl }: { 
  name: string; 
  confirmationUrl?: string; 
}) => (
  <div style={{ fontFamily: 'Arial, sans-serif', maxWidth: '600px' }}>
    <h1>Welcome, {name}!</h1>
    <p>We're excited to have you on board.</p>
    {confirmationUrl && (
      <p>
        <a href={confirmationUrl} style={{ 
          backgroundColor: '#007bff', 
          color: 'white', 
          padding: '10px 20px', 
          textDecoration: 'none',
          borderRadius: '4px' 
        }}>
          Confirm Email
        </a>
      </p>
    )}
  </div>
);

const templates = {
  welcome: WelcomeEmail,
};

// Create client with templates - types are fully inferred
const client = createEmailClient({
  smtp: {
    host: 'smtp.example.com',
    port: 587,
    auth: {
      user: '[email protected]',
      pass: 'password',
    },
  },
  templates,
  defaults: {
    from: '[email protected]',
  },
});

// Send email with full type safety
await client.sendTemplate('welcome', {
  from: '[email protected]',
  to: '[email protected]',
  subject: 'Welcome to our service!',
  props: {
    name: 'John Doe',
    confirmationUrl: 'https://example.com/confirm/123',
  },
});

API Reference

createEmailClient<T>(config: EmailClientConfig<T>): SMTPClient<T>

Creates a new email client with type-safe template support.

Configuration

interface EmailClientConfig<T extends TemplateRecord> {
  smtp: SMTPConfig;
  templates: T;
  defaults?: {
    from?: string | Address;
    replyTo?: string | Address;
  };
}

interface SMTPConfig {
  host: string;
  port: number;
  secure?: boolean;
  auth?: {
    user: string;
    pass: string;
  };
  tls?: {
    rejectUnauthorized?: boolean;
    servername?: string;
  };
  pool?: boolean;
  maxConnections?: number;
  maxMessages?: number;
  rateLimit?: number;
  logger?: boolean;
  debug?: boolean;
}

Client Methods

send(options: PlainEmailOptions): Promise<SendResult>

Send a plain text or HTML email.

await client.send({
  from: '[email protected]',
  to: '[email protected]',
  subject: 'Plain email',
  text: 'This is a plain text email',
  html: '<p>This is an HTML email</p>',
});

sendTemplate<K>(template: K, options): Promise<SendResult>

Send an email using a React template with type-safe props.

await client.sendTemplate('welcome', {
  from: '[email protected]',
  to: '[email protected]',
  subject: 'Welcome!',
  props: { name: 'John', confirmationUrl: 'https://...' },
});

verify(): Promise<boolean>

Verify the SMTP connection.

close(): Promise<void>

Close the SMTP connection.

getTemplateNames(): string[]

Get available template names.

Built-in Template Examples

Welcome Email

interface WelcomeEmailProps {
  name: string;
  confirmationUrl?: string;
}

const WelcomeEmail = ({ name, confirmationUrl }: WelcomeEmailProps) => (
  <html>
    <head>
      <meta charSet="utf-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Welcome!</title>
    </head>
    <body style={{ margin: 0, padding: 0, backgroundColor: '#f4f4f4' }}>
      <div style={{
        fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
        lineHeight: 1.6,
        color: '#333',
        maxWidth: '600px',
        margin: '0 auto',
        padding: '20px',
      }}>
        <h1 style={{ color: '#2c3e50', marginBottom: '20px' }}>
          Welcome, {name}!
        </h1>
        <p>
          We're excited to have you on board. Your account has been successfully created.
        </p>
        {confirmationUrl && (
          <>
            <p>Please confirm your email address by clicking the button below:</p>
            <p style={{ textAlign: 'center', margin: '30px 0' }}>
              <a href={confirmationUrl} style={{
                display: 'inline-block',
                padding: '12px 24px',
                backgroundColor: '#3498db',
                color: '#ffffff',
                textDecoration: 'none',
                borderRadius: '4px',
                fontWeight: 'bold',
              }}>
                Confirm Email
              </a>
            </p>
          </>
        )}
        <div style={{
          marginTop: '40px',
          paddingTop: '20px',
          borderTop: '1px solid #eee',
          fontSize: '14px',
          color: '#666',
        }}>
          <p>If you have any questions, feel free to reply to this email.</p>
          <p>Best regards,<br />The Team</p>
        </div>
      </div>
    </body>
  </html>
);

Password Reset Email

interface PasswordResetEmailProps {
  name: string;
  resetUrl: string;
  expiresIn: string;
}

const PasswordResetEmail = ({ name, resetUrl, expiresIn }: PasswordResetEmailProps) => (
  <html>
    <head>
      <meta charSet="utf-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Password Reset Request</title>
    </head>
    <body style={{ margin: 0, padding: 0, backgroundColor: '#f4f4f4' }}>
      <div style={{
        fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
        lineHeight: 1.6,
        color: '#333',
        maxWidth: '600px',
        margin: '0 auto',
        padding: '20px',
      }}>
        <h1 style={{ color: '#2c3e50', marginBottom: '20px' }}>
          Password Reset Request
        </h1>
        <p>Hi {name},</p>
        <p>
          We received a request to reset your password. Click the button below to create a new password:
        </p>
        <p style={{ textAlign: 'center', margin: '30px 0' }}>
          <a href={resetUrl} style={{
            display: 'inline-block',
            padding: '12px 24px',
            backgroundColor: '#3498db',
            color: '#ffffff',
            textDecoration: 'none',
            borderRadius: '4px',
            fontWeight: 'bold',
          }}>
            Reset Password
          </a>
        </p>
        <p>
          This link will expire in {expiresIn}. If you didn't request a password reset,
          you can safely ignore this email.
        </p>
        <div style={{
          marginTop: '40px',
          paddingTop: '20px',
          borderTop: '1px solid #eee',
          fontSize: '14px',
          color: '#666',
        }}>
          <p>For security reasons, this link can only be used once.</p>
        </div>
      </div>
    </body>
  </html>
);

Notification Email

interface NotificationEmailProps {
  name: string;
  title: string;
  message: string;
  actionUrl?: string;
  actionText?: string;
}

const NotificationEmail = ({ 
  name, 
  title, 
  message, 
  actionUrl, 
  actionText = 'View Details' 
}: NotificationEmailProps) => (
  <html>
    <head>
      <meta charSet="utf-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>{title}</title>
    </head>
    <body style={{ margin: 0, padding: 0, backgroundColor: '#f4f4f4' }}>
      <div style={{
        fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
        lineHeight: 1.6,
        color: '#333',
        maxWidth: '600px',
        margin: '0 auto',
        padding: '20px',
      }}>
        <h1 style={{ color: '#2c3e50', marginBottom: '20px' }}>
          {title}
        </h1>
        <p>Hi {name},</p>
        <p>{message}</p>
        {actionUrl && (
          <p style={{ textAlign: 'center', margin: '30px 0' }}>
            <a href={actionUrl} style={{
              display: 'inline-block',
              padding: '12px 24px',
              backgroundColor: '#3498db',
              color: '#ffffff',
              textDecoration: 'none',
              borderRadius: '4px',
              fontWeight: 'bold',
            }}>
              {actionText}
            </a>
          </p>
        )}
        <div style={{
          marginTop: '40px',
          paddingTop: '20px',
          borderTop: '1px solid #eee',
          fontSize: '14px',
          color: '#666',
        }}>
          <p>This is an automated notification from our system.</p>
        </div>
      </div>
    </body>
  </html>
);

Multiple Templates Example

import { createEmailClient } from '@geekmidas/emailkit';

const templates = {
  welcome: WelcomeEmail,
  passwordReset: PasswordResetEmail,
  notification: NotificationEmail,
};

const client = createEmailClient({
  smtp: {
    host: 'smtp.example.com',
    port: 587,
    auth: {
      user: '[email protected]',
      pass: 'password',
    },
  },
  templates,
  defaults: {
    from: '[email protected]',
  },
});

// All template names and props are fully type-safe
await client.sendTemplate('welcome', {
  from: '[email protected]',
  to: '[email protected]',
  subject: 'Welcome to our service!',
  props: { name: 'John Doe', confirmationUrl: 'https://example.com/confirm/123' },
});

await client.sendTemplate('passwordReset', {
  from: '[email protected]',
  to: '[email protected]',
  subject: 'Reset your password',
  props: { name: 'John Doe', resetUrl: 'https://example.com/reset/456', expiresIn: '24 hours' },
});

await client.sendTemplate('notification', {
  from: '[email protected]',
  to: '[email protected]',
  subject: 'Important notification',
  props: { 
    name: 'John Doe', 
    title: 'Account Update', 
    message: 'Your account settings have been updated.',
    actionUrl: 'https://example.com/settings',
    actionText: 'View Settings' 
  },
});

TypeScript Support

The library provides full TypeScript support with:

  • Template name inference - Only valid template names are accepted
  • Props type checking - Props are validated based on the template's prop types
  • Autocomplete support - IDE autocomplete for template names and props
  • Compile-time safety - Catch template and prop errors at build time

License

MIT