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

@uxf/mailing

v13.0.2

Published

Email rendering utilities and build tools

Readme

@uxf/mailing

Tooling for authoring react-email templates and rendering them to HTML from Node — an esbuild-based production build step, a tsx dev runner, responsive layout helpers, and a preview-props helper.

When to use

Use this in a project that writes transactional emails as React (react-email) components and needs to turn them into HTML from a Node/CLI process (in UXF projects a PHP backend shells out to Node to produce the final HTML). It provides:

  • build-renderers — bundles each template into a standalone, self-executing .js renderer.
  • dev-runner — renders a single template on the fly with tsx, no build step.
  • responsive — ResponsiveRow / ResponsiveColumn layout helpers for email-safe multi-column rows.
  • with-preview-props — attaches preview data to a template for the react-email preview UI.

It is not an email-sending package (no SMTP/transport) and not a component library — the email components (Html, Body, Text, Tailwind, render, …) come from the react-email peer dependency.

Installation

yarn add @uxf/mailing
  • ESM-only ("type": "module") and requires Node >= 24.
  • Peer dependencies the consuming project must provide: react ^19.3.0, react-dom ^19.3.0, react-email ^6.11.0.
  • tsx ^4.23.12 is also a peer dependency. The package ships its entry points as raw .ts/.tsx, so build-renderers and dev-runner are executed with tsx rather than node — see Build & run. npm installs it automatically; yarn and pnpm need it added explicitly.
  • Bundled dependencies (nothing to install): esbuild, glob, yargs, dotenv.

Public entry points

The package ships an exports map — import only these subpaths (there is no root/index export):

| Import path | Kind | Exports | | --------------------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | @uxf/mailing/with-preview-props | module | withPreviewProps | | @uxf/mailing/responsive | module | ResponsiveRow, ResponsiveColumn, isResponsiveColumn, createResponsiveRow, createResponsiveColumn, and types ResponsiveRowProps, ResponsiveColumnProps, BaseSectionProps | | @uxf/mailing/types | types | EmailOptions<Data>, AnyObject, BuildResult | | @uxf/mailing/build-renderers | CLI script | run via tsx (see Build & run) | | @uxf/mailing/dev-runner | CLI script | run via tsx (see Build & run) |

renderer-entry.tsx and renderer-plugin.ts are internal build machinery and are not part of the public surface.

Quick start

A template is a .tsx file that exports a named EmailComponent (rendered to HTML) plus a default export that wires up preview data for the react-email preview UI. The component receives EmailOptions-shaped props ({ data }).

// templates/react/my-template.tsx
import { Body, Container, Head, Html, pixelBasedPreset, Tailwind, Text } from "react-email";
import { withPreviewProps } from "@uxf/mailing/with-preview-props";
import previewProps from "./my-template.json";

export function EmailComponent(props: { data: { title: string; message: string } }) {
    return (
        <Tailwind config={{ presets: [pixelBasedPreset] }}>
            <Html lang="cs">
                <Head>
                    <title>{props.data.title}</title>
                </Head>
                <Body className="mx-auto max-w-[600px] p-5 font-sans">
                    <Container>
                        <Text>{props.data.message}</Text>
                    </Container>
                </Body>
            </Html>
        </Tailwind>
    );
}

export default function MyTemplate() {
    return withPreviewProps(EmailComponent, previewProps);
}
// templates/react/my-template.json
{
    "data": {
        "title": "My Email Template",
        "message": "Hello from my custom template!"
    }
}

Render it in dev, or build a production bundle:

# dev: render on the fly (no build)
tsx node_modules/@uxf/mailing/dev-runner.tsx templates/react/my-template.tsx '{"data": {"title": "Hi", "message": "Hello"}}'

# production: bundle every template under the path into a sibling .js
tsx node_modules/@uxf/mailing/build-renderers.ts --path templates/react

The JSON argument is the top-level EmailOptions object; its data field is passed to the component as props.data.

API

withPreviewProps

import { withPreviewProps } from "@uxf/mailing/with-preview-props";

withPreviewProps<Data extends AnyObject, Props extends EmailOptions<Data>>(
    Component: FunctionComponent<Props>,
    props: Props,
): ReactElement;

Attaches props to Component.PreviewProps (consumed by the react-email preview UI) and returns <Component data={props.data} />. Use it in the template's default export, passing the named EmailComponent and the imported preview JSON.

responsive

Email-safe multi-column layout built from nested tables. Columns are declared with span (relative width); rows warn in the console above 3 columns.

import { ResponsiveColumn, ResponsiveRow } from "@uxf/mailing/responsive";

<ResponsiveRow maxWidth={600} paddingLeft={16} paddingRight={16}>
    <ResponsiveColumn span={2} style={{ backgroundColor: "green" }} />
    <ResponsiveColumn span={1} style={{ backgroundColor: "red" }} />
</ResponsiveRow>;
  • ResponsiveRowProps — table attributes plus maxWidth, paddingLeft, paddingRight, paddingTop, paddingBottom (numbers, in px). padding* and maxWidth are removed from the style prop and set via the dedicated props instead. maxWidth (default 600) is the width of the whole row, left and right padding included; the columns share what is left in proportion to their span.
  • ResponsiveColumnProps — table attributes plus span?: number (default 1) and tdProps (forwarded to the inner <td>).
  • isResponsiveColumn(node) — type guard; createResponsiveRow / createResponsiveColumn are the factories the default ResponsiveRow / ResponsiveColumn are built from.

types

import type { AnyObject, BuildResult, EmailOptions } from "@uxf/mailing/types";
  • EmailOptions<Data extends AnyObject = AnyObject> — { data: Data }, the props shape every template receives.
  • AnyObject — Record<string, any>.
  • BuildResult — per-file result metadata produced by build-renderers.

Build & run

build-renderers (production)

tsx node_modules/@uxf/mailing/build-renderers.ts --path templates/react
  • --path, -p (required) — templates directory. Globs every **/*.tsx under it.
  • Bundles each template with esbuild (ESM, minified, target: es2022, platform: node, JSX automatic) into a .js file next to the source.
  • Externals (resolved from the runtime's node_modules, not inlined): react, react-dom, react/jsx-runtime, react-email, yargs.

Each bundle is a self-executing renderer. Run it with a JSON argument or a --config file:

# JSON string
node templates/react/my-template.js '{"data": {"title": "Test", "message": "Hello"}}'

# or read the JSON from a file
node templates/react/my-template.js --config templates/react/my-template.json

It renders the template's named EmailComponent and prints the HTML to stdout.

dev-runner (development)

tsx node_modules/@uxf/mailing/dev-runner.tsx <template-path> <json-data>

Dynamically imports the template's named EmailComponent, renders it with the given JSON, and prints the HTML. No build step; it also loads a project .env via dotenv/config.

Environment variables

Templates can read process.env at render time, e.g.:

<Img alt="Logo" src={`${process.env.FRONTEND_URL}/assets/mailing/logo.png`} />

dev-runner loads variables from the project .env (dotenv/config). Production .js bundles do not load .env themselves — the caller must supply the environment.

tsconfig requirements

The consuming project's tsconfig.json must set jsx: "react-jsx" and include the templates directory:

{
    "compilerOptions": {
        "jsx": "react-jsx"
    },
    "include": ["templates/react/**/*.ts", "templates/react/**/*.tsx"]
}

Gotchas

  • ESM + Node ≥ 24 only. The package has no root export — always import from a subpath listed above.
  • Every template must export a named EmailComponent (this is what gets rendered) and a default function (supplies PreviewProps for the preview UI). The runners import EmailComponent, not the default.
  • Template files must end in .tsx; build-renderers only globs **/*.tsx.
  • react, react-dom, react-email (and yargs) are external in built bundles — they must be installed in the runtime's node_modules.
  • Keep to at most 3 ResponsiveColumns per ResponsiveRow; more logs a console warning. Set row padding/maxWidth via the dedicated props, not style.

Troubleshooting

  • React is not defined at runtime — the tsconfig.json include does not cover the template files; ensure templates/react/** is included and jsx: "react-jsx" is set.
  • Build failures — confirm templates end with .tsx, each exports a named EmailComponent plus a default function, and run tsc --noEmit (yarn typecheck) to surface type errors.