Framework-agnostic TypeScript DSL for building email-safe HTML with React and Vue preview support
npm install emaildslA framework-agnostic TypeScript DSL for building email-safe HTML.
- 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.
``bash`
pnpm add emaildslor
npm install emaildsl
For local development or to contribute, clone the repository:
`bash`
git clone https://github.com/veri5ied/emaildsl.git
cd emaildsl
pnpm install
pnpm build
`typescript
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();
`
`tsx
import { EmailPreview } from "emaildsl/react";
import { email, section, text } from "emaildsl";
const myEmail = email({
body: [section([text("Hello")])],
});
function App() {
return
}
`
`vue
`
- section(children, options) - Creates a layout section (renders as table row)
- column(children, options) - Creates a column within a section (renders as table cell)
- 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)
`typescript`
email({
title: string; // Email title (appears in
body: Primitive[]; // Array of primitives
theme?: Theme; // Optional global theme
lang?: string; // Language code (default: 'en')
});
`typescript`
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;
};
}
Every primitive accepts a style option for inline CSS overrides:
`typescript`
text("Hello", {
style: {
fontSize: "24px",
fontWeight: "bold",
color: "#333333",
},
});
Style priority (highest to lowest):
1. Element-level style optiontheme
2. Global configuration
3. Built-in defaults
`typescript
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();
`
`typescript
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" },
}),
]),
],
});
`
`typescript
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%" },
),
]),
],
});
`
`typescript
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" }),
]),
],
});
`
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
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
EmailDSL abstracts away the complexity:
`typescript
// Instead of this:
;
Hello World
// Write this:
section([text("Hello World")]);
`
- Node.js 18+
- pnpm
`bash`
git clone https://github.com/veri5ied/emaildsl.git
cd emaildsl
pnpm install
`bash`
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
``
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
EmailDSL is written in TypeScript and provides full type safety:
`typescript
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
},
}),
]),
],
});
`
- [x] Core TypeScript DSL
- [x] HTML renderer with table-based layouts
- [x] Inline style generation
- [x] Global theme system
- [x] Component-level style overrides
- [x] Publish to npm
- [x] React renderer (optional, for live previews)
- [x] 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
Contributions are welcome! Please follow these steps:
1. Fork the repository
2. Create a feature branch (git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature'
3. Commit your changes ()git push origin feature/amazing-feature
4. Push to the branch ()
5. Open a Pull Request
Please ensure:
- All tests pass (pnpm test)pnpm lint`)
- Code is linted (
- TypeScript types are correct
- You've added tests for new features
MIT License - see LICENSE file for details.
- Issues: GitHub Issues
- Discussions: Coming soon
- Documentation: Coming soon
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.