A powerful, visual, and block-based email template builder plugin for Payload CMS β built on top of React Email. Design beautiful, dynamic, and localized email templates with ease! β¨
- π§© Visual, block-based email template builder (no raw JSX required)
- ποΈ Custom blocks: Heading, Button, Container, Image, Row, Section, Text, and more
- π§ Dynamic macros: Variables, functions, dates, conditions, loops, and config values
- π Preview: See your email as you build, with device and zoom controls
- π Localization: Localize templates and content
- π API endpoints: Generate both HTML and PlainText before sending your email
pnpm add payload-email-template
# or
yarn add payload-email-template
# or
npm install payload-email-templateAdd the plugin to your Payload config in the plugins array:
import { emailTemplatePlugin } from 'payload-email-template'
export default buildConfig({
// ...other config
plugins: [
emailTemplatePlugin({
enabled: true,
imageCollectionSlug: 'media', // (optional) collection for image uploads
previewBreakpoints: [
// (optional) default breakpoints
{ name: 'mobile', label: 'Mobile', width: 375, height: 667 },
{ name: 'desktop', label: 'Desktop', width: 1440, height: 900 },
],
disableStyle: false, // (optional) allow custom style overrides, default: false
macros: {
// (optional) dynamic content for variables, functions, and config
variables: {
companyName: 'Your Company',
user: { firstName: 'John', lastName: 'Doe' },
},
functions: {
greet: (name) => `Hello, ${name}!`,
formatPrice: (price) => `$${price.toFixed(2)}`,
},
config: {
appName: 'My App',
version: '1.0.0',
},
},
// ...other options
}),
],
})| Option | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | true |
Enable/disable the plugin |
imageCollectionSlug |
string | 'media' |
Collection slug for image uploads |
previewBreakpoints |
array | see example | Device preview sizes for the preview tab |
disableStyle |
boolean | false |
Disable custom style overrides |
macros |
object | {} |
Dynamic content configuration (variables, functions, config) |
endpointAccess |
Access | ({req}) => Boolean(req.user) |
Default access control for the /api/email-templates/:id/generate endpoint |
collectionAccess |
Access | { read: ({req}) => Boolean(req.user) } |
Default access control for email-templates collection |
Configure blocks (Heading, Button, Container, etc.) to build your template. Each block has configurable fields (content, style, alignment, etc.). Blocks can be nested for complex layouts.
If you enable localization in your Payload config, the plugin will automatically make text-related template fields localizable.
The template can be previewed in the Preview tab. You can also use the controls to toggle mode, device, and zoom.
You can trigger rendering the email template by sending a POST request to the following endpoint:
POST /api/email-templates/:id/generate
You will receive both html and plainText versions of the template:
{
"html": "<html>...</html>",
"plainText": "..."
}Then you can send it via your email provider.
It's also possible to render the email template by calling renderEmailTemplate directly in the back-end, skipping the http request in that case.
import { renderEmailTemplate } from "payload-email-template"
// const emailTemplate = await req.payload.find({
// collection: 'email-templates',
// ...
// })
const html = await renderEmailTemplate({
data: emailTemplate,
locale: 'en',
format: 'html',
macroContext: {
variables: { ... },
functions: { ... },
config: { ... }
}
})The plugin supports powerful dynamic content through macros that can be used in email subjects, headings, and text blocks.
Access data from your macro configuration:
{{companyName}} β "Acme Corporation"
{{user.firstName}} β "John"
Access plugin configuration values:
{{@config('appName')}} β "My Awesome App"
{{@config('version')}} β "1.0.0"
Format current date and time:
{{@date('YYYY-MM-DD')}} β "2024-01-15"
{{@date('MMMM Do, YYYY')}} β "January 15th, 2024"
Transform data with custom functions:
{{@uppercase('hello')}} β "HELLO"
{{@greet('John')}} β "Hello, John!" (if configured)
Show content based on conditions:
- Set up conditions in the macro block interface
- Define content for true/false scenarios
- Useful for personalized content
Repeat content for data collections:
- Configure collection data source
- Define template for each item
- Great for product lists, etc.
β
Email Subjects: "Welcome to {{companyName}}, {{user.firstName}}!"
β Heading Blocks: Mix text, links, and macros in headings
β Text Blocks: Inline macros alongside regular text and links
β Macro Blocks: Dedicated blocks for complex conditions and loops
You can also pass runtime macro context when generating emails:
// POST /api/email-templates/:id/generate
{
"macroContext": {
"variables": {
"user": { "firstName": "Jane" },
"orderTotal": "$99.99"
}
}
}Runtime context takes precedence over plugin configuration.
Contributions are welcome! Please open issues or pull requests for bug fixes, features, or documentation improvements.

