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

@keycloakify/angular-email

v1.1.4

Published

Angular Email Builder

Readme

Angular Email

Angular Email is a library that enables email template development using Angular, inspired by jsx-email. It provides a way to create email components using Angular's templating system.

Installation

To install Angular Email, use npm or yarn:

npm install @keycloakify/angular-email
# or
yarn add @keycloakify/angular-email

Usage

| Angular | Tailwind CSS | @keycloakify/angular-email | Maintained | | ------- | ------------ | -------------------------- | ------------- | | 20 | 4.x+ | 1.x+ | Yes | | 20 | 3.x+ | 0.x+ | Bugfixes only |

Creating an Email Component

see this example

Rendering the Email

To render the email as HTML or plaintext, use Angular's rendering engine:

// email.component.ts
...
import { render, RenderToHtml } from '@keycloakify/angular-email';

...
export class EmailComponent {
  ....
}

type EmailComponentProps = {};

export const renderToHtml: RenderToHtml<EmailComponentProps> = (props) => {
  return render({
    component: EmailComponent,
    selector: 'app-root',
    props,
    options: {
      pretty: true,
    },
  });
};
# cmd

export EMAIL_COMPONENTS_DIR_PATH="src/emails"
export EMAIL_OUTPUT_DIR_PATH="dist/emails"
export EMAIL_EXTERNAL_PACKAGES="tailwindcss,@tailwindcss/postcss,postcss,postcss-calc,postcss-custom-properties,postcss-preset-env,postcss-logical"

npx keycloakify-angular-email build -p "$EMAIL_COMPONENTS_DIR_PATH" -o "$EMAIL_OUTPUT_DIR_PATH" -e "$EMAIL_EXTERNAL_PACKAGES"

NB: use keycloakify-angular-email build when you don't need to pass dynamic inputs to your components, otherwise see Standalone Dynamic Rendering

With Keycloakify Emails

see Email POC for a full example

// emails/tsconfig.json

{
  "extends": "../tsconfig.json",
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "../out-tsc/emails",
    "types": []
  },
  "files": [],
  "include": ["*.ts", "**/*.ts"]
}
// email.component.ts
...
import { render } from '@keycloakify/angular-email';
import type { GetSubject, GetTemplate } from 'keycloakify-emails';

...
export class EmailComponent {
  ....
}

export const getTemplate: GetTemplate = async (props) => {
  return await render({
    component: EmailComponent,
    props,
    selector: 'kc-email-test',
    options: {
      signalInputsPrefix: '$',
      pretty: true,
      plainText: props.plainText,
    },
  });
};

export const getSubject: GetSubject = async (_props) => {
  return '[KEYCLOAK] - SMTP test message';
};
// vite.config.ts

...
import { buildEmailTheme } from 'keycloakify-emails';
import { angularEsbuildPlugin } from '@keycloakify/angular-email/esbuild';

export default defineConfig(({ mode }) => ({
  ...
  plugins: [
    angular(),
    keycloakify({
      ...
      postBuild: async (buildContext) => {
        await buildEmailTheme({
          templatesSrcDirPath: join(import.meta.dirname, 'emails', 'templates'),
          filterTemplate: (filePath: string) => !!filePath.endsWith('.component.ts'),
          themeNames: buildContext.themeNames,
          keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath,
          locales: ['en'],
          cwd: import.meta.dirname,
          i18nSourceFile: join(import.meta.dirname, 'emails', 'i18n.ts'),
          environmentVariables: buildContext.environmentVariables,
          assetsDirPath: join(import.meta.dirname, 'emails', 'templates', 'assets'),
          esbuild: {
            packages: 'bundle',
            external: ['juice', '...other packages you might use to process css'],
            format: 'esm',
            outExtension: { '.js': '.mjs' },
            plugins: [angularEsbuildPlugin(join(import.meta.dirname, 'emails'))],
          },
        });
      },
    }),
  ],
}));

Standalone Dynamic Rendering

Use it in a server environment

// index.mjs

import { toHTML } from '@keycloakify/angular-email/node';

toHTML({
  filePath: 'path/to/your.component.ts',
  props: { foo: 'bar' },
  externals: [],
})
  .then((html) => {
    console.log(html);
  })
  .catch((e) => {
    console.error(e);
  });

or

// index.cjs

const { toHTML } = require('@keycloakify/angular-email/node');

toHTML({
  filePath: 'path/to/your.component.ts',
  props: { foo: 'bar' },
  externals: [],
})
  .then((html) => {
    console.log(html);
  })
  .catch((e) => {
    console.error(e);
  });
# cmd

node index.mjs # or node index.cjs

API

@keycloakify/angular-email

Render

type Render<Input extends Record<string, any>> = {
  component: Type<unknown>;
  /** Component selector */
  selector: string;
  /** Component inputs */
  props?: Input;
  options?: {
    /** render as text */
    plainText?: boolean;
    /** format the html output */
    pretty?: boolean;
    /** Optional hook to manipulate the extracted CSS. Useful for PostCSS processing */
    cssProcessor?: (css: string, html: string) => Promise<string>;
    /** if you use prefix conventions on signal inputs */
    signalInputsPrefix?: string;
  };
};

render()

render<Input extends Record<string, any>>({ component, selector, props, options }: Render<Input>) => Promise<string>

@keycloakify/angular-email/esbuild

angularEsbuildPlugin()

angularEsbuildPlugin(cwd: string) => Plugin

@keycloakify/angular-email/node

toHTML()

toHTML<Input extends Record<string, any>>(options: {
    filePath: string;
    props?: Input;
    root?: string;
    externals?: string[];
}) => Promise<string>

@keycloakify/angular-email/tailwindcss-preset-email

Just a tailwind v4 preset, inspired by @maizzle/tailwindcss

/* styles.css */
@import '@keycloakify/angular-email/tailwindcss-preset-email';
// email.component.ts
...
import { Component, ViewEncapsulation } from '@angular/core';
import { render, RenderToHtml } from '@keycloakify/angular-email';
// or your custom css processor implementation
import { cssProcessor } from '@keycloakify/angular-email/tailwindcss-preset-email/css-processor';


...
@Component({
  ...
  styleUrls: ['styles.css'],
  encapsulation: ViewEncapsulation.None,
})
export class EmailComponent {
  ....
}

type EmailComponentProps = {};

export const renderToHtml: RenderToHtml<EmailComponentProps> = (props) => {
  return render({
    component: EmailComponent,
    selector: 'app-root',
    props,
    options: {
      pretty: true,
      cssProcessor,
    },
  });
};

Contributing

Contributions are welcome! Feel free to open an issue or submit a pull request on GitHub.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Acknowledgments