scaf-email
v1.0.1
Published
A TypeScript library for designing and generating responsive HTML email templates.
Maintainers
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 scafGetting 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.tsThis makes email templates easier to maintain and reuse.
Development
Clone the repository:
git clone <repository-url>
cd scafInstall dependencies:
npm installBuild the package:
npm run buildRun the development build:
npm run devProject Structure
scaf/
├── src/
│ ├── components/
│ ├── templates/
│ ├── types.ts
│ └── index.ts
│
├── dist/
├── package.json
├── tsconfig.json
├── README.md
└── LICENSERoadmap
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:
- Open an issue.
- Describe the problem or proposed feature.
- 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.
