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.
To install Angular Email, use npm or yarn:
npm install @keycloakify/angular-email
# or
yarn add @keycloakify/angular-email
see this example
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"
npx keycloakify-angular-email build -p $EMAIL_COMPONENTS_DIR_PATH
NB: use keycloakify-angular-email build
when you don't need to pass dynamic inputs to your components, otherwise see Standalone Dynamic Rendering
// 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,
esbuild: {
packages: 'bundle',
external: ['juice', 'postcss', 'tailwindcss-v3'],
format: 'esm',
outExtension: { '.js': '.mjs' },
plugins: [angularEsbuildPlugin(import.meta.dirname)],
},
});
},
}),
],
}));
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' },
})
.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' },
})
.then((html) => {
console.log(html);
})
.catch((e) => {
console.error(e);
});
# cmd
node index.mjs # or node index.cjs
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;
/** tailwind v3 configuration object */
tailwindConfig?: Partial<Config>;
/** if you use prefix conventions on signal inputs */
signalInputsPrefix?: string;
};
};
render<Input extends Record<string, any>>({ component, selector, props, options }: Render<Input>) => Promise<string>
@keycloakify/angular-email/esbuild
8000angularEsbuildPlugin(cwd: string) => Plugin
toHTML<Input extends Record<string, any>>(options: {
filePath: string;
props?: Input;
root?: string;
}) => Promise<string>
Just a tailwind v3 preset, inspired by @maizzle/tailwindcss-preset-email
NB: tailwind v4 is not supported due to high level css generation and poor support in overriding default utilities
add support for disabling core plugins
Cannot override tailwind utilities
Contributions are welcome! Feel free to open an issue or submit a pull request on GitHub.
This project is licensed under the MIT License. See the LICENSE file for details.
- Inspired by jsx-email
- Developed by Luca Peruzzo