Skip to content

Veri5ied/emaildsl

Repository files navigation

EmailDSL

A framework-agnostic TypeScript DSL for building email-safe HTML.

Features

  • Email-safe: Framework generates tables and inline styles automatically.
  • Themable: Global theme support with component overrides.
  • Responsive: Fluid layouts that work on mobile (with stacking support).
  • TypeScript: Full type safety for all primitives.
  • Zero dependencies: Lightweight and fast.

Installation

From NPM

pnpm add emaildsl
# or
npm install emaildsl

Local Development

For local development or to contribute, clone the repository:

git clone https://github.com/veri5ied/emaildsl.git
cd emaildsl
pnpm install
pnpm build

Usage

HTML (Framework Agnostic)

import { email, section, text, button } from "emaildsl";

const myEmail = email({
  title: "Hello",
  body: [
    section([
      text("Hello World"),
      button("Click Me", { href: "https://example.com" }),
    ]),
  ],
});

const html = myEmail.render();

React (Live Preview)

import { EmailPreview } from "emaildsl/react";
import { email, section, text } from "emaildsl";

const myEmail = email({
  body: [section([text("Hello")])],
});

function App() {
  return <EmailPreview config={myEmail.config} />;
}

Vue (Live Preview)

<script setup>
import { EmailPreview } from "emaildsl/vue";
import { email, section, text } from "emaildsl";

const myEmail = email({
  body: [section([text("Hello")])],
});
</script>

<template>
  <EmailPreview :config="myEmail.config" />
</template>

Primitives

Layout Primitives

  • section(children, options) - Creates a layout section (renders as table row)
  • column(children, options) - Creates a column within a section (renders as table cell)

Content Primitives

  • text(content, options) - Creates a text element with optional styling
  • button(label, options) - Creates a clickable button with href
  • image(src, options) - Creates an image element with alt text and dimensions
  • divider(options) - Creates a horizontal divider line
  • spacer(height) - Creates vertical spacing (accepts px or em)

API Reference

Email Configuration

email({
  title: string;              // Email title (appears in <title> tag)
  body: Primitive[];          // Array of primitives
  theme?: Theme;              // Optional global theme
  lang?: string;              // Language code (default: 'en')
});

Theme Options

theme: {
  colors?: {
    primary?: string;
    secondary?: string;
    text?: string;
    background?: string;
  };
  fonts?: {
    family?: string;
    size?: string;
  };
  spacing?: {
    section?: string;
    element?: string;
  };
  button?: {
    borderRadius?: string;
    padding?: string;
  };
}

Styling System

Every primitive accepts a style option for inline CSS overrides:

text("Hello", {
  style: {
    fontSize: "24px",
    fontWeight: "bold",
    color: "#333333",
  },
});

Style priority (highest to lowest):

  1. Element-level style option
  2. Global theme configuration
  3. Built-in defaults

Examples

Welcome Email

import { email, section, text, button, divider } from "emaildsl";

const welcomeEmail = email({
  title: "Welcome to Our Platform",
  theme: {
    colors: {
      primary: "#4CAF50",
      text: "#333333",
    },
  },
  body: [
    section([
      text("Welcome!", { style: { fontSize: "24px", fontWeight: "bold" } }),
      text("We're excited to have you on board."),
      button("Get Started", {
        href: "https://example.com/onboarding",
        style: { backgroundColor: "#4CAF50" },
      }),
      divider(),
      text("Questions? Reply to this email.", {
        style: { fontSize: "12px", color: "#666666" },
      }),
    ]),
  ],
});

const html = welcomeEmail.render();

Receipt Email

import { email, section, text, divider } from "emaildsl";

const receipt = email({
  title: "Order Receipt",
  body: [
    section([
      text("Order Confirmation", { style: { fontSize: "24px" } }),
      text("Order #12345"),
      divider(),
      text("Product Name"),
      text("$99.00", { style: { fontWeight: "bold" } }),
      text("Shipping: $5.00"),
      divider(),
      text("Total: $104.00", {
        style: { fontSize: "18px", fontWeight: "bold" },
      }),
    ]),
  ],
});

Multi-column Layout

import { email, section, column, text } from "emaildsl";

const newsletter = email({
  body: [
    section([
      column(
        [
          text("Column 1 Header", { style: { fontWeight: "bold" } }),
          text("Left side content goes here."),
        ],
        { width: "50%" },
      ),
      column(
        [
          text("Column 2 Header", { style: { fontWeight: "bold" } }),
          text("Right side content goes here."),
        ],
        { width: "50%" },
      ),
    ]),
  ],
});

Advanced Theming

import { email, section, text, button } from "emaildsl";

const themedEmail = email({
  theme: {
    colors: {
      primary: "#2196F3",
      secondary: "#FFC107",
      text: "#212121",
      background: "#FAFAFA",
    },
    fonts: {
      family: "Helvetica, Arial, sans-serif",
      size: "16px",
    },
    spacing: {
      section: "32px",
      element: "16px",
    },
    button: {
      borderRadius: "8px",
      padding: "14px 28px",
    },
  },
  body: [
    section([
      text("Themed Email"),
      button("Action Button", { href: "https://example.com" }),
    ]),
  ],
});

Email Client Support

EmailDSL generates HTML that works across all major email clients:

  • Gmail (web, iOS, Android)
  • Outlook 2016/2019/365 (Windows)
  • Outlook.com
  • Apple Mail (macOS, iOS)
  • Yahoo Mail
  • AOL Mail
  • Thunderbird
  • And more

Why EmailDSL?

The Problem

Writing HTML emails is notoriously difficult:

  • Email clients use outdated rendering engines
  • Modern CSS (Flexbox, Grid) doesn't work
  • Styles must be inline
  • Tables are required for layout
  • Each client has unique quirks

The Solution

EmailDSL abstracts away the complexity:

// Instead of this:
<table cellpadding="0" cellspacing="0" border="0" width="100%">
  <tr>
    <td style="padding: 20px; font-family: Arial, sans-serif; font-size: 16px; color: #333333;">
      Hello World
    </td>
  </tr>
</table>;

// Write this:
section([text("Hello World")]);

Development

Prerequisites

  • Node.js 18+
  • pnpm

Setup

git clone https://github.com/veri5ied/emaildsl.git
cd emaildsl
pnpm install

Commands

pnpm dev      # Watch mode with auto-rebuild
pnpm build    # Build for production
pnpm test     # Run tests
pnpm test:ui  # Run tests with UI
pnpm lint     # Lint code

Project Structure

emaildsl/
├── src/
│   ├── primitives/     # DSL primitive implementations
│   ├── renderer/       # HTML rendering logic
│   ├── types/          # TypeScript definitions
│   └── index.ts        # Main export
├── examples/           # Example email templates
├── tests/              # Unit + integration tests
└── package.json

TypeScript Support

EmailDSL is written in TypeScript and provides full type safety:

import { email, section, text } from "emaildsl";

// TypeScript will catch errors:
email({
  title: 123, // ❌ Error: Type 'number' is not assignable to type 'string'
  body: [
    section([
      text("Hello", {
        style: {
          color: "red",
          fontWeight: "bold",
          invalidProp: true, // ❌ Error: Object literal may only specify known properties
        },
      }),
    ]),
  ],
});

Roadmap

  • Core TypeScript DSL
  • HTML renderer with table-based layouts
  • Inline style generation
  • Global theme system
  • Component-level style overrides
  • Publish to npm
  • React renderer (optional, for live previews)
  • Vue renderer (optional)
  • Svelte renderer (optional)
  • Framework-agnostic usage in all JS environments
  • Pre-built email template library
  • Visual email builder
  • Email testing utilities
  • Integration with email sending services

Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Please ensure:

  • All tests pass (pnpm test)
  • Code is linted (pnpm lint)
  • TypeScript types are correct
  • You've added tests for new features

License

MIT License - see LICENSE file for details.

Support

  • Issues: GitHub Issues
  • Discussions: Coming soon
  • Documentation: Coming soon

Acknowledgments

EmailDSL was created to solve the universal pain of writing cross-client compatible email HTML. It draws inspiration from React Email and MJML while maintaining complete framework independence.


Built with TypeScript. Tested across major email clients.

About

Declarative DSL for building responsive, email-safe HTML emails

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published