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

scaf-email

v1.0.1

Published

A TypeScript library for designing and generating responsive HTML email templates.

Readme

Scaf

Scaf is a TypeScript library for building reusable, structured, and customizable HTML email templates.

It provides a component-based API that makes it easy to create professional email layouts without manually writing large amounts of HTML and inline CSS.

Scaf generates standard HTML, so the resulting email can be used with virtually any email delivery service, including AWS SES, SendGrid, Resend, Nodemailer, and more.

✨ Features

  • 📧 Build reusable HTML email templates
  • 🧩 Component-based email design
  • 🎨 Customizable component styles
  • 📱 Email-friendly responsive layouts
  • 🔷 Full TypeScript support
  • 🏗️ Compose complex emails from simple components
  • 🔌 Works with any email delivery provider
  • 🚀 Easy integration with Node.js and NestJS
  • 📦 Lightweight and dependency-friendly

Installation

Install Scaf using npm:

npm install scaf

Getting Started

Scaf provides a simple SCAF API for composing email templates.

import { SCAF } from "scaf";

const html = SCAF.layout([
  SCAF.title("Welcome to Scaf!", {
    align: "center",
  }),

  SCAF.greeting("Hi ", "John Doe"),

  SCAF.paragraph("Welcome to our platform. We are happy to have you with us."),

  SCAF.button({
    label: "Get Started",
    href: "https://example.com",
  }),
]);

console.log(html);

The generated HTML can be passed directly to your email provider.

await sendEmail({
  to: "[email protected]",
  subject: "Welcome",
  html,
});

Layout

SCAF.layout() is the main container for composing an email.

Each component is passed as an item in the layout array.

const html = SCAF.layout([
  SCAF.title("Welcome!"),

  SCAF.greeting("John"),

  SCAF.paragraph("Thank you for joining our platform."),

  SCAF.button({
    label: "Visit Website",
    href: "https://example.com",
  }),
]);

This approach allows you to build an email by combining reusable components instead of manually managing HTML.


Components

Scaf provides a collection of reusable email components.

Title

Create a large heading.

SCAF.title("Admission Success!", {
  marginTop: 20,
  align: "center",
});

Institute Header

Institute Header

SCAF.instHeader() creates a reusable header for institutes, schools, universities, organizations, and other branded email templates.

It supports multiple layout variants and provides options for customizing the logo, alignment, colors, typography, spacing, borders, and overall appearance.

Basic Usage

SCAF.instHeader({
  title: "ABC EDUCATION INSTITUTE",
  subtitle: "Excellence in Education & Learning",
  logo: "https://example.com/logo.png",
});

Default Values

You can also call SCAF.instHeader() without any arguments.

SCAF.instHeader();

The default configuration is:

{
  title: 'ABC EDUCATION INSTITUTE',
  subtitle: 'Excellence in Education & Learning',
  logo: 'https://erp.eduayna.com/ayna.png',
  variant: 'default',
  align: 'left',
  logoPosition: 'left',
  background: '#F5F5F5',
  titleColor: '#F97316',
  subtitleColor: '#6B7280',
  borderRadius: 8,
  border: 'none',
  padding: '24px 28px',
  logoWidth: 40,
  logoHeight: 40,
  logoBorderRadius: 0,
  titleFontSize: 16,
  subtitleFontSize: 12,
  titleFontWeight: 700,
  gap: 14,
  fontFamily: 'Arial,Helvetica,sans-serif',
}

Options

| Option | Type | Default | Description | | ------------------ | ------------------------------------------------------------- | -------------------------------------- | ----------------------------------------------- | | title | string | 'ABC EDUCATION INSTITUTE' | Main organization or institute name | | subtitle | string | 'Excellence in Education & Learning' | Secondary information displayed below the title | | logo | string | Default logo URL | Logo image URL | | variant | 'default' \| 'centered' \| 'minimal' \| 'brand' \| 'banner' | 'default' | Controls the header layout | | align | 'left' \| 'center' \| 'right' | 'left' | Controls content alignment | | logoPosition | 'left' \| 'top' | 'left' | Controls the logo position | | background | string | '#F5F5F5' | Header background color | | titleColor | string | '#F97316' | Title text color | | subtitleColor | string | '#6B7280' | Subtitle text color | | borderRadius | number | 8 | Header border radius | | border | string | 'none' | CSS border value | | padding | string | '24px 28px' | Header padding | | logoWidth | number | 40 | Logo width in pixels | | logoHeight | number | 40 | Logo height in pixels | | logoBorderRadius | number | 0 | Logo border radius in pixels | | titleFontSize | number | 16 | Title font size | | subtitleFontSize | number | 12 | Subtitle font size | | titleFontWeight | number \| string | 700 | Title font weight | | gap | number | 14 | Space between logo and text | | fontFamily | string | 'Arial,Helvetica,sans-serif' | Font family used by the header |


Variants

instHeader() provides five built-in variants.

Default

The standard horizontal header with the logo on the left.

SCAF.instHeader({
  title: "ABC EDUCATION INSTITUTE",
  subtitle: "Excellence in Education & Learning",
  variant: "default",
});

Centered

Places the logo above the organization information and centers the content.

SCAF.instHeader({
  title: "ABC EDUCATION INSTITUTE",
  subtitle: "Excellence in Education & Learning",
  variant: "centered",
});

Suitable for admission confirmations, certificates, official notices, and similar emails.

Minimal

Creates a compact header with smaller typography and spacing.

SCAF.instHeader({
  title: "ABC EDUCATION INSTITUTE",
  subtitle: "Excellence in Education & Learning",
  variant: "minimal",
});

Useful when the email contains a large amount of content.

Brand

Creates a larger header that gives more emphasis to the organization's branding.

SCAF.instHeader({
  title: "ABC EDUCATION INSTITUTE",
  subtitle: "Excellence in Education & Learning",
  variant: "brand",
});

Banner

Creates a prominent centered header with a larger logo and typography.

SCAF.instHeader({
  title: "Admission Successful",
  subtitle: "Your application has been successfully processed.",
  variant: "banner",
});

Custom Alignment

You can override the alignment independently of the selected variant.

SCAF.instHeader({
  title: "ABC EDUCATION INSTITUTE",
  subtitle: "Excellence in Education & Learning",
  align: "center",
});

Supported values:

"left" | "center" | "right";

Logo Position

The logo can be displayed beside the organization information or above it.

Logo on the Left

SCAF.instHeader({
  title: "ABC EDUCATION INSTITUTE",
  subtitle: "Excellence in Education & Learning",
  logoPosition: "left",
});

Logo on Top

SCAF.instHeader({
  title: "ABC EDUCATION INSTITUTE",
  subtitle: "Excellence in Education & Learning",
  logoPosition: "top",
  align: "center",
});

Custom Styling

All major visual properties can be customized.

SCAF.instHeader({
  title: "GREENFIELD UNIVERSITY",
  subtitle: "Dhaka, Bangladesh",

  logo: "https://example.com/logo.png",

  background: "#EFF6FF",
  titleColor: "#1D4ED8",
  subtitleColor: "#475569",

  borderRadius: 12,
  border: "1px solid #DBEAFE",
  padding: "28px 32px",

  logoWidth: 52,
  logoHeight: 52,
  logoBorderRadius: 8,

  titleFontSize: 20,
  subtitleFontSize: 13,
  titleFontWeight: 700,

  gap: 16,
});

Without a Subtitle

The subtitle is optional.

SCAF.instHeader({
  title: "ABC EDUCATION INSTITUTE",
  subtitle: "",
});

When the subtitle is empty, Scaf automatically removes the subtitle section.


Example

SCAF.layout([
  SCAF.title("Admission Success!", {
    align: "center",
  }),

  SCAF.instHeader({
    title: "JAMALPUR SCIENCE & TECHNOLOGY UNIVERSITY",
    subtitle: "Melandaha, Jamalpur-2012",
    logo: "https://erp.eduayna.com/ayna.png",

    variant: "brand",

    background: "#F5F5F5",
    titleColor: "#F97316",
    subtitleColor: "#6B7280",

    borderRadius: 12,
    padding: "24px 28px",

    logoWidth: 50,
    logoHeight: 50,
    logoBorderRadius: 8,

    titleFontSize: 18,
    subtitleFontSize: 12,
    gap: 16,
  }),

  SCAF.greeting("Hi ", "John Doe"),

  SCAF.paragraph("Your admission application has been successfully processed."),
]);

API

SCAF.instHeader(input?: {
  title?: string;
  subtitle?: string;
  logo?: string;

  variant?: 'default' | 'centered' | 'minimal' | 'brand' | 'banner';

  align?: 'left' | 'center' | 'right';

  logoPosition?: 'left' | 'top';

  background?: string;
  titleColor?: string;
  subtitleColor?: string;

  borderRadius?: number;
  border?: string;
  padding?: string;

  logoWidth?: number;
  logoHeight?: number;
  logoBorderRadius?: number;

  titleFontSize?: number;
  subtitleFontSize?: number;
  titleFontWeight?: number | string;

  gap?: number;

  fontFamily?: string;
}): HtmlFragment;

Greeting

Create a standard greeting section.

SCAF.greeting("John Doe");

Paragraph

Create paragraphs and combine them with formatting components.

SCAF.paragraph(
  "This is ",
  SCAF.bold("bold text"),
  ", ",
  SCAF.italic("italic text"),
  ", and ",
  SCAF.underline("underlined text"),
);

Text Formatting

Scaf provides several inline formatting helpers.

Bold

SCAF.bold("Important text");

Italic

SCAF.italic("Italic text");

Underline

SCAF.underline("Underlined text");

Inline Code

SCAF.code('const password = "123456";');

Tables

Standard Table

Create a horizontal table with headers and rows.

SCAF.table(
  {
    headers: ["Subject", "Mark", "Grade", "GPA"],
    rows: [
      ["Bangla 1st", "80", "A+", "4.3"],
      ["English 1st", "72", "A+", "4.3"],
      ["Math", "95", "A+", "4.3"],
    ],
  },
  {
    title: "Final Exam - 2026",
  },
);

Vertical Table

Create a key-value style table.

SCAF.verticalTable([
  {
    key: "Institute",
    value: "ABC International School",
  },
  {
    key: "Username",
    value: "01712345678",
  },
  {
    key: "Password",
    value: "Abc@12345",
  },
  {
    key: "Portal",
    value: "https://portal.example.com",
    isLink: true,
  },
]);

This is particularly useful for:

  • Login credentials
  • Application information
  • Payment information
  • Student information
  • Configuration details

Lists

Create ordered or unordered lists.

SCAF.list(["Step 1", "Step 2", "Step 3"], {
  ordered: true,
});

For an unordered list:

SCAF.list(["First item", "Second item", "Third item"]);

Quotes

Scaf provides two quote components.

Quote

SCAF.quote("Education is the passport to the future.", "Nelson Mandela");

Quote 2

quote2 provides a more customizable notification-style quote.

SCAF.quote2("Your application has been reviewed successfully.", {
  borderColor: "#22C55E",
  background: "#F0FDF4",
  color: "#166534",
  quoteColor: "#16A34A",
});

Timeline

Create a timeline for displaying progress or status history.

SCAF.timeline([
  {
    title: "Application Submitted",
    description: "We have received your application.",
    active: true,
  },
  {
    title: "Under Review",
    description: "Our team is reviewing your documents.",
    active: true,
  },
  {
    title: "Admission Confirmed",
    description: "Waiting for confirmation.",
  },
]);

Progress

Display progress using a progress bar.

SCAF.progress(75, {
  label: "Application Progress",
});

Badges

Use badges to display statuses.

SCAF.badge("Activated");

Custom colors can also be provided:

SCAF.badge("Pending", "#92400e", "#fef3c7");

Example:

SCAF.paragraph(
  "Current status: ",
  SCAF.badge("Activated"),
  " ",
  SCAF.badge("Pending", "#92400e", "#fef3c7"),
  " ",
  SCAF.badge("Failed", "#b91c1c", "#fee2e2"),
);

Links

Create email-safe links.

SCAF.link("EDUAYNA", "https://eduayna.com");

Links can also be embedded inside paragraphs.

SCAF.paragraph(
  "Visit ",
  SCAF.link("EDUAYNA", "https://eduayna.com"),
  " to continue.",
);

QR Code

Generate a QR code inside the email.

SCAF.qrCode("https://eduayna.com/verify/123456", {
  title: "Verify Document",
  subtitle: "Scan with your mobile camera",
  size: 180,
  showValue: true,
});

Useful for:

  • Document verification
  • Payment verification
  • Application tracking
  • Login links
  • Event registration

OTP

Create a one-time-password display.

SCAF.otp("481923", {
  title: "Your Verification Code",
  subtitle: "Use this one-time password to continue.",
  expiresIn: "10 minutes",
});

Code Block

Display formatted code or command-line instructions.

SCAF.codeBlock(
  `npm install

npm run build

pm2 restart api`,
  {
    language: "Shell",
  },
);

Grid

Create a multi-column layout.

SCAF.grid(
  [
    SCAF.paragraph("First item"),
    SCAF.paragraph("Second item"),
    SCAF.paragraph("Third item"),
    SCAF.paragraph("Fourth item"),
    SCAF.paragraph("Fifth item"),
  ],
  {
    columns: 3,
    align: "center",
    border: "1px solid gray",
  },
);

The grid is useful for displaying cards, summaries, statistics, or grouped information.


Notice

Create an informational notice.

SCAF.notice({
  title: "Security Notice",
  body: "Please change your password after your first login.",
});

Divider

Add a visual separator between sections.

SCAF.divider();

Button

Create a call-to-action button.

SCAF.button({
  label: "Login to EDUAYNA",
  href: "https://portal.eduayna.com",
});

You can also specify a button variant:

SCAF.button({
  label: "Login to EDUAYNA",
  href: "https://portal.eduayna.com",
  variant: "outline",
});

Spacer

Add vertical spacing between components.

SCAF.spacer(20);

Raw HTML

When you need to insert custom HTML, use SCAF.raw().

SCAF.raw(htmlFooter);

This is useful when integrating existing HTML fragments or custom footer templates.


Complete Example

The following example demonstrates how multiple Scaf components can be combined into a complete email.

import { SCAF } from "scaf-email";
import { htmlFooter } from "./scaf/scaffold.const";

const html = SCAF.layout([
  SCAF.title("Admission Success!", {
    marginTop: 20,
    align: "center",
  }),

  SCAF.instHeader({
    title: "JAMALPUR SCIENCE & TECHNOLOGY UNIVERSITY",
    subtitle: "Melandaha, Jamalpur-2012",
    logo: "https://erp.eduayna.com/ayna.png",
    background: "#F5F5F5",
    borderRadius: 12,
  }),

  SCAF.greeting("John Doe"),

  SCAF.paragraph("Your admission application has been successfully processed."),

  SCAF.table(
    {
      headers: ["Subject", "Mark", "Grade", "GPA"],
      rows: [
        ["Bangla 1st", "80", "A+", "4.3"],
        ["English 1st", "72", "A+", "4.3"],
        ["Math", "95", "A+", "4.3"],
      ],
    },
    {
      title: "Final Exam - 2026",
    },
  ),

  SCAF.subtitle("Application Status"),

  SCAF.quote2("Your application has been reviewed successfully.", {
    borderColor: "#22C55E",
    background: "#F0FDF4",
    color: "#166534",
    quoteColor: "#16A34A",
  }),

  SCAF.timeline([
    {
      title: "Application Submitted",
      description: "We have received your application.",
      active: true,
    },
    {
      title: "Under Review",
      description: "Our team is reviewing your documents.",
      active: true,
    },
    {
      title: "Admission Confirmed",
      description: "Waiting for confirmation.",
    },
  ]),

  SCAF.progress(75, {
    label: "Application Progress",
  }),

  SCAF.verticalTable([
    {
      key: "Institute",
      value: "ABC International School",
    },
    {
      key: "Username",
      value: "01712345678",
    },
    {
      key: "Portal",
      value: "https://portal.eduayna.com",
      isLink: true,
    },
  ]),

  SCAF.notice({
    title: "Security Notice",
    body: "Please change your password after your first login.",
  }),

  SCAF.divider(),

  SCAF.button({
    label: "Login to EDUAYNA",
    href: "https://portal.eduayna.com",
    variant: "outline",
  }),

  SCAF.spacer(20),

  SCAF.raw(htmlFooter),
]);

console.log(html);

Using Scaf with NestJS

Scaf works naturally with NestJS applications.

You can create reusable email functions:

import { SCAF } from "scaf-email";

export function WelcomeEmail(name: string) {
  return SCAF.layout([
    SCAF.title("Welcome to Our Platform", {
      align: "center",
    }),

    SCAF.greeting(name),

    SCAF.paragraph("Thank you for joining our platform."),

    SCAF.button({
      label: "Login",
      href: "https://example.com/login",
    }),
  ]);
}

Then use the generated HTML with your existing mail service:

const html = WelcomeEmail("John");

await this.mailService.sendMail({
  to: "[email protected]",
  subject: "Welcome to our platform",
  html,
});

Scaf does not handle email delivery. It focuses on HTML email generation, allowing you to keep email design independent from your delivery infrastructure.


Using Scaf with AWS SES

Because Scaf produces HTML, it can be used directly with AWS SES.

const html = WelcomeEmail("John");

await ses.sendEmail({
  Destination: {
    ToAddresses: ["[email protected]"],
  },

  Message: {
    Subject: {
      Data: "Welcome",
    },

    Body: {
      Html: {
        Data: html,
      },
    },
  },

  Source: "[email protected]",
});

The same generated HTML can also be used with other email providers.


Recommended Project Structure

For a larger application, email templates can be organized separately from the application logic.

src/
├── email/
│   ├── templates/
│   │   ├── welcome.email.ts
│   │   ├── admission-success.email.ts
│   │   └── password-reset.email.ts
│   │
│   ├── components/
│   │   └── footer.ts
│   │
│   └── index.ts
│
├── modules/
│   └── ...
│
└── main.ts

This makes email templates easier to maintain and reuse.


Development

Clone the repository:

git clone <repository-url>
cd scaf

Install dependencies:

npm install

Build the package:

npm run build

Run the development build:

npm run dev

Project Structure

scaf/
├── src/
│   ├── components/
│   ├── templates/
│   ├── types.ts
│   └── index.ts
│
├── dist/
├── package.json
├── tsconfig.json
├── README.md
└── LICENSE

Roadmap

Planned improvements include:

  • [ ] Additional reusable email components
  • [ ] More responsive layout utilities
  • [ ] Pre-built email templates
  • [ ] Theme support
  • [ ] Dark-mode support
  • [ ] Email preview utilities
  • [ ] More styling options
  • [ ] Advanced template customization
  • [ ] MJML-inspired component system

Contributing

Contributions are welcome.

If you find a bug, have an idea, or want to propose a new component:

  1. Open an issue.
  2. Describe the problem or proposed feature.
  3. Submit a pull request if you have an implementation.

Please keep components reusable, email-client friendly, and TypeScript compatible.


License

Scaf is released under the MIT License.