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

everydayai-email-generator

v1.0.14

Published

A TypeScript wrapper for MJML to simplify email generation

Readme

Email Generator

A powerful TypeScript wrapper for MJML that simplifies professional email generation with a fluent API, standardised styling, and component-based architecture.

Table of Contents

Installation

npm install everydayai-email-generator

Quick Start

The Email Generator provides a fluent API for building professional emails with consistent styling and responsive design.

import { createEmail } from 'everydayai-email-generator';

// Create a example email with multiple components
const email = createEmail()
  .newSection()
  .header('Monthly Report', 'Performance summary for December 2024')
  .endSection()
  .newSection()
  .textSection('Thank you for your continued partnership. This is an example of a text section with an optional header included', 'Introduction')
  .metricsSection('Key Performance Indicators', [
    { value: '$125,000', description: '+12% vs last month' },
    { value: '248', description: '+8% growth' },
  ])
  .endSection()
  .newSection()
  .barGraphSection('Quarterly Comparison', [
    { label: 'Q1', value: 85 },
    { label: 'Q2', value: 92 },
    { label: 'Q3', value: 78 }
  ])
  .barListSection('Updated Contact Fields', [
    { label: 'Phone Numbers', value: 5842 },
    { label: 'Email Addresses', value: 4231 },
    { label: 'Addresses', value: 3927 },
    { label: 'Names', value: 2814 },
    { label: 'Other Fields', value: 1642 }
  ], 'Scaled against 7,000 total updates.', 7000, true)
  .progressBarSection('Annual Target Progress', 73, 'Goal: $500k by year end')
  .endSection();

// Render to HTML
const result = email.render();

Result: Example Email

The resulting HTML can be used with any email service that accepts HTML content and paired with something like Nodemailer to distribute the email.

API Reference

Core Functions

createEmail()

Creates a new EmailBuilder instance with a fluent API for building emails. This is the starting point for building an email.

Returns: EmailBuilder

const email = createEmail();

EmailBuilder Methods

All methods return the EmailBuilder instance for method chaining, enabling a fluent API pattern.

render(options?): RenderResult

Renders the email to HTML using MJML.

Parameters:

  • options (RenderOptions, optional): Rendering configuration (advanced usage)

Returns: RenderResult with html string and optional errors array

const result = email.render({ minify: true, beautify: false });

getMjml(): string

Gets the raw MJML markup for the email without rendering to HTML.

Returns: string - The complete MJML document

const mjmlMarkup = email.getMjml();

Components

Section Layout Components

Control the visual grouping and separation of email sections. All components are rendered with white rectangular backgrounds that can be chained together. To create different email sections using visual grouping for separation of content, you can use the newSection() and endSection() methods.

newSection(): EmailBuilder

Starts a new email section with rounded top corners and proper spacing.

Features:

  • Creates visual separation from previous content/starts the email
  • Rounded top corners only
  • Proper margin and padding
  • White background

endSection(): EmailBuilder

Ends an email section with rounded bottom corners and proper spacing.

Features:

  • Creates visual separation for next content
  • Rounded bottom corners only
  • Proper margin and padding
  • Complements newSection() for grouped content

Example (With and without sectioning): Take this example of a simple email with no sectioning:

const email = createEmail()
      .header('Here\'s some components with no sectioning', 'This is a subtitle')
      .textSection('This is a text section with an optional header included', 'Introduction')
      .metricsSection('Key Performance Indicators', [
        { value: '$125,000', description: '+12% vs last month' },
        { value: '248', description: '+8% growth' },
      ])
      .textSection('This is a text section explaining the bargraph without an optional header included')
      .barGraphSection('Quarterly Comparison', [
        { label: 'Q1', value: 85 },
        { label: 'Q2', value: 92 },
        { label: 'Q3', value: 78 }
      ])

No Sectioning Visual Example:

Example Email

And now with sectioning:

const email = createEmail()
  .newSection()
  .header('Here\'s some components with no sectioning', 'This is a subtitle')
  .endSection()
  .newSection()
  .textSection('This is a text section with an optional header included', 'Introduction')
  .endSection()
  .newSection()
  .metricsSection('Key Performance Indicators', [
    { value: '$125,000', description: '+12% vs last month' },
    { value: '248', description: '+8% growth' },
  ])
  .endSection()
  .newSection()
  .textSection('This is a text section explaining the bargraph without an optional header included')
  .barGraphSection('Quarterly Comparison', [
    { label: 'Q1', value: 85 },
    { label: 'Q2', value: 92 },
    { label: 'Q3', value: 78 }
  ])
  .endSection()

Sectioning Visual Example: Example Email

Header Component

Creates a prominent header section with title and optional subtitle.

header(title: string, subtitle?: string): EmailBuilder

Parameters:

  • title (string): The main header text (required)
  • subtitle (string, optional): Optional subtitle displayed below the title

Features:

  • Large, bold title text
  • Left-aligned layout
  • Optional subtitle with smaller font
  • Consistent spacing and styling

Example:

const email = createEmail()
  .newSection()
  .header('Monthly Performance Report', '2025 Q2')
  .endSection()
  

Visual Example: Example Email


Text Section Component

Creates a content section with formatted text and optional title.

textSection(content: string, title?: string): EmailBuilder

Parameters:

  • content (string): The main text content (required)
  • title (string, optional): Optional section title displayed above content

Features:

  • Readable typography with optimal line height
  • HTML escaping for security
  • Optional section titles
  • Responsive text layout

Example:

const email = createEmail()
  .newSection()
  .textSection('Thank you for your continued partnership with our services.')
  .textSection('Our team has been working hard to improve...', 'Updates')
  .endSection()

Visual Example: Example Email


Image Component

Creates an embedded image block from a publicly accessible URL, with optional title and subtitle text above the image.

imageComponent(imageUrl: string, options?: ImageComponentOptions): EmailBuilder

Parameters:

  • imageUrl (string): Publicly accessible image URL to embed (required)
  • options (ImageComponentOptions, optional): Optional configuration object Includes title, subtitle, altText, and width

Features:

  • Gmail-friendly hosted image embedding
  • Optional title and subtitle above the image
  • Full-width responsive image rendering by default
  • Useful for charts, screenshots, and report graphics

Example:

const email = createEmail()
  .newSection()
  .imageComponent(
    'https://storage.googleapis.com/logo-storage-eai/performanceGraphRw.png',
    {
      title: 'Data Quality Protection',
      altText: 'Performance graph showing maintained quality over time',
    }
  )
  .endSection()

Visual Example: Example Email


Metrics Section Component

Creates a dashboard-style metrics display with cards in a responsive grid layout.

metricsSection(title: string, metrics: MetricItem[], subtitle?: string, variant?: MetricsSectionVariant): EmailBuilder

Parameters:

  • title (string): The main section title (required)
  • metrics (MetricItem[]): Array of metric objects (required)
  • subtitle (string, optional): Optional section subtitle
  • variant ('outline' | 'filled', optional): Card style variant. Defaults to 'outline'

Features:

  • Responsive grid layout
  • Card-based design with rounded corners
  • Automatic 2-column layout for standard metric sets
  • Automatic 3-column layout when the metric count is divisible by 3
  • Cards align flush with the section width while preserving internal spacing
  • Optional filled cream card variant for summary-style metric rows
  • Support for metric labels, values, and descriptions
  • Consistent spacing and typography

Example:

Standard 2-column outline cards:

const email = createEmail()
  .newSection()
  .metricsSection('Initial Data Reset Results', [
    { value: '47,892', description: 'Records Processed' },
    { value: '18,456', description: 'Data Inconsistencies Corrected' },
    { value: '6,214', description: 'Duplicates Resolved' },
    { value: '38%', description: 'Records Corrected' }
  ])
  .endSection()

3-up filled cards:

const email = createEmail()
  .newSection()
  .metricsSection('Impact Summary', [
    { value: '247', description: 'Hours Saved (Initial Reset)' },
    { value: '$8,645', description: 'Cost Equivalent Avoided' },
    { value: '41,678', description: 'Clean Records' }
  ], undefined, 'filled')
  .endSection()

Visual Example: Example Email


Table Section Component

Creates a professional data table with headers and rows.

tableSection(title: string, tableData: TableData, subtitle?: string): EmailBuilder

Parameters:

  • title (string): The main section title (required)
  • tableData (TableData): Object containing headers and rows (required)
  • subtitle (string, optional): Optional section subtitle

Features:

  • Responsive table design
  • Header row with distinct styling
  • Mobile-friendly layout

Example:

const email = createEmail()
  .newSection()
  .tableSection('Sales Performance', {
    headers: ['Region', 'Sales', 'Growth'],
    rows: [
      { cells: ['North', '$45,000', '+12%'] },
      { cells: ['South', '$38,000', '+8%'] },
      { cells: ['East', '$52,000', '+15%'] },
      { cells: ['West', '$41,000', '+6%'] }
    ]
  }, 'Regional breakdown')
  .endSection()

Visual Example: Example Email


Bar Graph Component

Creates a visual bar chart with up to 3 bars using company brand colours.

barGraphSection(title: string, bars: BarData[], subtitle?: string): EmailBuilder

Parameters:

  • title (string): The main section title (required)
  • bars (BarData[]): Array of bar data objects, maximum 3 bars (required)
  • subtitle (string, optional): Optional section subtitle

Features:

  • Automatic scaling relative to largest value
  • Company brand colours (blue, green, orange)
  • Responsive bar sizing
  • Label and value display
  • Maximum of 3 bars for optimal readability

Example:

const email = createEmail()
  .newSection()
  .barGraphSection('Quarterly Comparison', [
    { label: 'Q1', value: 85, subtitle: 'Strong start' },
    { label: 'Q2', value: 92, subtitle: 'Peak performance' },
    { label: 'Q3', value: 78, subtitle: 'Seasonal dip' }
  ], 'Performance by quarter')
  .endSection()

Visual Example: Example Email


Bar List Component

Creates a horizontal bar list with labels on the left, values aligned on the right, and each bar scaled against either an explicit total or the largest supplied value.

barListSection(title: string, bars: BarListData[], subtitle?: string, total?: number, contained?: boolean): EmailBuilder

Parameters:

  • title (string): The section title
  • bars (BarListData[]): The horizontal bar items to render
  • subtitle (string, optional): Optional supporting copy above the bars
  • total (number, optional): Explicit total used to scale all bars. If omitted, the largest value becomes the full-width bar.
  • contained (boolean, optional): Renders the title and bar rows inside a cream card, with each row using an inline label, bar, and value layout.

Features:

  • Right-aligned amount labels for every row
  • Uses the same brand palette as the vertical bar graph, plus yellow and black when more colours are needed
  • Supports custom display values and custom colours per row
  • Falls back to max-value scaling when no total is provided
  • Optional contained card layout for denser comparison rows

Example:

const email = createEmail()
  .newSection()
  .barListSection('Contact Fields Updated', [
    { label: 'Phone Numbers', value: 5842 },
    { label: 'Email Addresses', value: 4231 },
    { label: 'Addresses', value: 3927 },
    { label: 'Names', value: 2814 },
    { label: 'Other Fields', value: 1642, colour: '#000000' }
  ], 'Bars scaled against a total of 18,456 updates.', 18456)
  .barListSection('Contact Fields Updated', [
    { label: 'Phone Numbers', value: 5842 },
    { label: 'Email Addresses', value: 4231 },
    { label: 'Addresses', value: 3927 },
    { label: 'Names', value: 2814 },
    { label: 'Other Fields', value: 1642 }
  ], 'No total supplied, so the largest value becomes the full-width bar.')
  .barListSection('Contact Duplicates Merged', [
    { label: 'Last 6 mths', value: 156, colour: '#FF702D' },
    { label: 'Last 30 days', value: 45, colour: '#66CC55' },
    { label: 'This week', value: 12, colour: '#0FB0EE' }
  ], undefined, undefined, true)
  .endSection()

Visual Example: Example Email


Report Intro Component

Creates a modular report opening block with a main title, optional support header, blue separator, and up to three follow-up text rows.

reportIntro(title: string, options?: ReportIntroOptions): EmailBuilder

Parameters:

  • title (string): The main report title
  • options (ReportIntroOptions, optional): Optional supporting content fields

Options:

  • subtitle (string, optional): Secondary heading below the title
  • primaryLine (string, optional): First black line under the separator
  • metadataItems (string[], optional): Grey metadata line joined by a separator
  • metadataSeparator (string, optional): Separator used between metadata items. Defaults to
  • footerLine (string, optional): Final black line

Features:

  • Large title and muted support header
  • Rounded blue separator pill
  • Clean options-object API so each line can be omitted independently
  • Suitable for report identity, dates, versions, and context

Example:

const email = createEmail()
  .newSection()
  .reportIntro('Ray White AI Data Integrity Report', {
    subtitle: 'Initial Data Reset',
    primaryLine: '{franchise_name}',
    metadataItems: ['October 1-31, 2025', 'Full Database Reset'],
    footerLine: 'Eve {version_number}',
  })
  .endSection()

Visual Example: Example Email


Highlighted Section Component

Creates a rounded stat callout with optional colour treatment and a right-aligned value.

highlightedSection(title: string, value?: string, tone?: HighlightedSectionTone, boldText?: boolean): EmailBuilder

Parameters:

  • title (string): The main stat label
  • value (string, optional): Optional value shown on the right
  • tone ('green' | 'yellow' | 'red' | 'neutral' | '', optional): Colour treatment. Use '' or 'neutral' for the cream version with black text.
  • boldText (boolean, optional): Whether the label and value should be bold. Defaults to true.

Features:

  • Green, yellow, red, or neutral cream styling
  • Right-aligned value layout
  • Smaller default text size than the original callout version
  • Optional non-bold rendering for neutral summary rows
  • Text-only callouts automatically render at normal body text size

Example:

const email = createEmail()
  .newSection()
  .highlightedSection('Total Fields Updated', '18,456', '', false)
  .highlightedSection('Total Duplicates Resolved', '6,214', 'green')
  .highlightedSection('Incomplete Fields Standardised', '482', 'yellow')
  .highlightedSection('High-Risk Records Flagged', '73', 'red')
  .endSection()

Visual Example: Example Email


Gradient Section Component

Creates a cream rounded insight card with a gradient progress bar, a movable black marker label, and supporting text above and below the bar.

gradientSection(markerLabel: string, percentage: number, topText: string, bottomText: string): EmailBuilder

Parameters:

  • markerLabel (string): Text shown inside the black marker pill
  • percentage (number): Marker position from 1 to 100
  • topText (string): Introductory copy inside the card above the bar
  • bottomText (string): Closing copy inside the card below the bar

Features:

  • Orange-to-blue-to-green gradient bar
  • Black marker label positioned from 1-100%
  • Supports lightweight **bold** text inside the top and bottom copy
  • Intentionally excludes title/subtitle so you can pair it with a normal header or text section above
  • Useful for capture quality, completion quality, or confidence-style metrics

Example:

const email = createEmail()
  .newSection()
  .textSection('Contact Capture Quality', 'Trends and Insights')
  .endSection()
  .newSection()
  .gradientSection(
    'You',
    72,
    'Of contacts added or updated this week, **72% were fully captured** with a name, phone number, email, and linked property.',
    "The remaining 28% are missing at least one field. Without a full set of details, it's harder to confidently match, merge, and enrich those records."
  )
  .endSection()

Visual Example: Example Email


Download Section Component

Creates a bordered cream download prompt with explanatory copy and a single in-panel download/open button.

downloadSection(title: string, content: string, buttonLabel: string, buttonUrl: string, inlineButtonLabel?: string, inlineButtonUrl?: string): EmailBuilder

Parameters:

  • title (string): Section title shown inside the bordered panel
  • content (string): Supporting explanation copy inside the panel
  • buttonLabel (string): Label for the in-panel button
  • buttonUrl (string): Destination URL for the in-panel button
  • inlineButtonLabel (string, optional): Optional override label for the in-panel button
  • inlineButtonUrl (string, optional): Optional override URL for the in-panel button

Features:

  • Cream bordered panel for contextual guidance
  • Single button rendered inside the panel
  • Optional inline button args let you override the displayed CTA without changing the base method shape
  • Supports lightweight **bold** text inside the content copy

Example:

const email = createEmail()
  .newSection()
  .downloadSection(
    'Possible Duplicates',
    "How to use this list: Eve thinks some of these accounts might be duplicates but wasn't sure enough to update them. Could you please take a look and update any duplicates directly in Vault if you agree.",
    'Download Duplicates (CSV)',
    'https://example.com/downloads/duplicates.csv',
    'Download CSV',
    'https://example.com/downloads/duplicates.csv'
  )
  .endSection()

Visual Example: Example Email


Hyperlink Button Component

Creates a clickable button that can be either full-width or compact right-aligned, with cream or black styling plus an optional metric-style bordered treatment.

hyperlinkButton(label: string, url: string, align?: 'full' | 'right', colour?: 'cream' | 'black', variant?: 'default' | 'metric', buttonImage?: 'downloadIcon'): EmailBuilder

Parameters:

  • label (string): The visible button text
  • url (string): The destination URL to open when clicked
  • align ('full' | 'right', optional): Layout mode. Defaults to 'full'
  • colour ('cream' | 'black', optional): Button colour style. Defaults to 'cream'
  • variant ('default' | 'metric', optional): Visual treatment. Use 'metric' for a white button with a thin cream border. Defaults to 'default'
  • buttonImage ('downloadIcon', optional): Optional inline icon shown to the left of the label

Features:

  • Full-width or compact right-aligned layout
  • Cream or black button styling
  • Optional metric-style white button with a thin cream border
  • Optional inline download icon
  • Rounded corners and clickable button body
  • Useful for download links, spreadsheets, dashboards, and client resources

Example:

const email = createEmail()
  .newSection()
  .hyperlinkButton(
    'Download All Changes (CSV)',
    'https://example.com/downloads/all-changes.csv',
    'full',
    'cream',
    'metric',
    'downloadIcon'
  )
  .hyperlinkButton(
    'Open Performance Spreadsheet',
    'https://example.com/reports/performance-sheet',
    'right',
    'black'
  )
  .endSection()

Visual Example: Example Email


Fact Section Component

Creates a cream callout for interesting context or interpretation, with an optional coloured accent on the left edge.

factSection(content: string, accentColour?: string): EmailBuilder

Parameters:

  • content (string): The fact or insight text to display
  • accentColour (string, optional): Optional left accent colour. Supports brand colour names like blue, green, yellow, orange, red, and black, or any CSS colour string.

Features:

  • Cream background that separates the text from white sections
  • Optional left accent edge inside the rounded container
  • Normal body text sizing for short callout paragraphs
  • Useful for insight statements, takeaways, or contextual notes

Example:

const email = createEmail()
  .newSection()
  .factSection('Resolving duplicates eliminates confusion, prevents conflicting data, and ensures your team works with a single source of truth for each contact and property.')
  .factSection('This baseline represents a fully reset system. Ongoing reports will focus on maintaining this standard as new data enters the database.', 'blue')
  .endSection()

Visual Example: Example Email


Footnote Section Component

Creates a light cream separator line followed by small muted supporting text.

footnoteSection(content: string): EmailBuilder

Parameters:

  • content (string): Footnote content. Supports line breaks and lightweight **bold** text.

Features:

  • Thin cream separator line
  • Small muted supporting copy
  • Useful for assumptions, calculation notes, and reporting caveats

Example:

const email = createEmail()
  .newSection()
  .footnoteSection(
    '* Hours saved: Based on 12,847 records × 1.15 min/record manual time\n* Cost saved: 247 hours × $35/hour average labor cost'
  )
  .endSection()

Visual Example: Example Email


Status Section Component

Creates a cream status card with a coloured title dot and as many bullet points as needed.

statusSection(title: string, items: string[], tone?: StatusSectionTone): EmailBuilder

Parameters:

  • title (string): The status heading shown beside the coloured dot
  • items (string[]): Array of bullet point lines to render under the title
  • tone ('green' | 'yellow' | 'red', optional): Colour used for the status dot

Features:

  • Cream card background matching the fact section
  • Green, yellow, or red status dot
  • Flexible bullet list length
  • Clean layout for summary/status callouts

Example:

const email = createEmail()
  .newSection()
  .statusSection('Database Status', [
    'All core datasets normalised and aligned',
    'Duplicate and conflict risks contained',
    'Contact data structured for ongoing use',
  ], 'green')
  .statusSection('Risk Status', [
    'Outstanding validation still required',
    'Manual review queue remains active',
  ], 'yellow')
  .endSection()

Visual Example: Example Email


Progress Bar Component

Creates a visual progress indicator showing percentage completion.

progressBarSection(title: string, percentage: number, subtitle?: string, showPercentage?: boolean, variant?: 'default' | 'headline'): EmailBuilder

Parameters:

  • title (string): The main section title (required)
  • percentage (number): Progress percentage from 0-100 (required)
  • subtitle (string, optional): Optional section subtitle
  • showPercentage (boolean, optional): Shows inline percentage text in the default variant when useful
  • variant ('default' | 'headline', optional): Visual style. Use 'headline' for the large centered percentage with a slim black bar

Features:

  • Orange fill colour matching brand
  • Rounded rectangle design
  • Percentage validation (0-100)
  • Smooth visual progression
  • Clear percentage display
  • Optional headline variant with centered large percentage and black slim bar

Example:

const email = createEmail()
  .newSection()
  .progressBarSection('Annual Target Progress', 73)
  .progressBarSection(
    'Neighbourhood Ownership Coverage',
    34,
    'Based on your active patch, you hold contact details for approximately 34% of property owners.',
    true,
    'headline'
  )
  .endSection()

Visual Example: Example Email