Skip to content

keycloakify/angular-email

Repository files navigation

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

About

Angular email builder

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •