This is a library for creating structured and styled HTML emails, intended as a transitional resource. Designed for convenience, it allows developers to build and customize emails quickly while encouraging best practices by illustrating the internal composition of emails through self-contained components. Inspired by Resend's @react-email.
This library takes a similar approach to the one applied by pilcrow's to The Copenhagen Book: this library is intended as a learning tool and a starting point. As developers become comfortable with the email structure and utilities provided, they are encouraged to transition toward standalone solutions.
To install the package, run:
npm install @uraniadev/emailer
This library provides a set of unstyled, modular email components (e.g.,
Button
, Container
, Heading
) built with Svelte and styled with Tailwind
CSS. Components use inline
styling through tw-to-css
to ensure email
compatibility.
Create an email using the provided components:
<!-- src/lib/email.svelte -->
<script>
import {
Button,
Container,
Heading,
Image,
Paragraph
} from "@uraniadev/emailer";
</script>
<Container>
<Image src="https://example.org/image-url.jpg" />
<Heading level={2}>Lorem ipsum dolor sit</Heading>
<Paragraph>
Lorem ipsum dolor sit amet consectetur adipisicing elit.
Maiores veritatis earum, perspiciatis pariatur exercitationem
illum eligendi amet,deserunt provident ipsum dolore!
Voluptas mollitia earum temporibus, hic consequatur
aperiam recusandae.
</Paragraph>
<Button href="https://www.example.com">Deserunt</Button>
</Container>
Then render this email in your server-side script:
import Emailer from "@uraniadev/emailer";
import Email from "./email.svelte";
const emailer = new Emailer();
const html = emailer.render(Email, {/* props */});
sendMail(html); // Use your preferred email-sending method
This library includes an inline
utility that merges Tailwind styles with
tw-to-css
to create compatible inline styles for emails:
import { inline } from "@uraniadev/emailer";
<p style={inline("text-lg text-pink-500 font-bold")}>
This is a formatted text
</p>;
// inline() inherith shadcn cn an apply tw-to-css inline:
import type { ClassValue } from "clsx";
import clsx from "clsx";
import { twMerge } from "tailwind-merge";
import { twi } from "tw-to-css";
export function inline(...inputs: ClassValue[]) {
return twi(twMerge(clsx(inputs)));
}
A link-styled button that accepts class
and href
attributes. *
<Button class="bg-blue-500 text-white" href="https://example.com">Click Me</Button>
A general-purpose card component for grouping content sections.
<Card class="shadow-lg">This is a card</Card>
A wrapper to align email content and provide consistent padding.
<Container class="max-w-lg">Content goes here</Container>
A responsive heading element allowing level-based customization.
<Heading level={2}>This is a Heading</Heading>
An image wrapper with optional classes.
<Image src="https://example.com/image.jpg" alt="Image description" />
For general text blocks, styled for readability.
<Paragraph>This is a paragraph of text</Paragraph>
This is a text snippet that appears under the subject line in the inbox but is hidden from the main email content when it’s opened. *
<Preview content="The preview of the content, to customize it from the actual mail" />
Generates repeated content, such as lists, from an array. itemsSnippet
can be
use to stylize the repeated item
<Repeatable items={[1, 2, 3]}>
{#snippet itemsSnippet(item)}
<Container>
<Paragraph>{item.name}</Paragraph>
</Container>
{/snippet}
</Repeatable>
Emailer
is the primary class used to render emails, taking in a Svelte
component and outputting an HTML template. It can be customized by passing
configuration options for props
, lang
, dir
, and style
.
class Emailer {
render<T extends Component<any>>(
component: T,
props?: ComponentProps<T>,
config?: HTMLConfig,
): string;
}
The htmlBoilerplate
function in the Emailer
class generates the complete
HTML structure for email content, applying essential styles and configuration
for better rendering across email clients. This function wraps the main content
(children
) in an HTML template, ensuring consistency and compatibility.
- props: A set of default styling properties for the
html
,body
, andcontainer
elements, configurable via theHTMLConfig
type. Each property is an array of style strings, providing styles like background color, text color, and padding. - dir: Defines text direction, with the default set to "ltr" (left-to-right). This can be adjusted based on the email's language requirements.
- lang: Specifies the language of the email content, set to "en" by default for English.
- style: A global style string that applies custom styling to the entire
HTML document, offering flexibility to embed CSS directly within the
<style>
tag.
The Emailer.render()
method uses htmlBoilerplate
to wrap the rendered body
of a Svelte component (provided in render
as component
). The function also
accepts:
- head: Optional custom content or metadata for the
<head>
section. - config: An optional
HTMLConfig
object to override the default properties, styles, direction, or language settings.
Together, these properties and htmlBoilerplate
facilitate the creation of
highly customizable, visually consistent email templates with minimal setup.
htmlBoilerplate = (children: string, head?: string, options?: HTMLConfig) => {
const { props, dir, lang, style } = options ||
{ props: this.props, dir: this.dir, lang: this.lang, style: this.style };
return `<!doctype html>
<html ${props?.html.join(" ")} dir=${dir} lang=${lang}>
<head>
<style>*{box-sizing:border-box;text-decoration:none;border:0;padding:0;margin:0;}${style}</style>
${head || this.head}
</head>
<body ${props?.body.join(" ")}>
<table ${props?.container.join(" ")}>
<tbody><tr><td>${children}</td></tr></tbody>
</table>
<body>
</html>`;
};
The library is structured as an auto-deprecating toolkit for email composition, encouraging developers to understand and apply best practices for maintainable email templates in production. The following approaches are suggested:
- Component Composition: Understand how each component, such as Container, Button, and Heading, is composed and utilize them to build reusable templates.
- Self-Managed Rendering: Implement Emailer on your server, simplifying future template updates and adhering to scalable, maintainable practices.
Drawing inspiration from resources like The Copenhagen Book, this library advocates for transparency in development practices and empowers developers to confidently transition to self-maintained code structures.
The following references provide further information on creating HTML emails:
- Good Email Code
- CanIEmail.com - Email HTML & CSS Compatibility
- Custom HTML Emails - Kevin Powell and Mark Robbins
Note: This library is intended as a learning tool and a starting point. As developers become comfortable with the email structure and utilities provided, they are encouraged to transition toward standalone solutions.