escwxyz/payload-email-template
A Payload CMS plugin to build email templates based on React Email
Payload Email Template Plugin ๐
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! โจ
โจ Features
- ๐งฉ 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
๐ฆ Installation
pnpm add payload-email-template
# or
yarn add payload-email-template
# or
npm install payload-email-template๐ Getting Started
Add 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
}),
],
})๐ผ๏ธ Demo
โ๏ธ Plugin 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 |
๐ ๏ธ Usage
๐งฑ Blocks
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.
๐ Localization
If you enable localization in your Payload config, the plugin will automatically make text-related template fields localizable.
๐ Preview
The template can be previewed in the Preview tab. You can also use the controls to toggle mode, device, and zoom.
๐ API Endpoints
Generate Email Template
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.
โ Local Api
Generate Email Template
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: { ... }
}
})๐ง Macros
The plugin supports powerful dynamic content through macros that can be used in email subjects, headings, and text blocks.
Macro Types
1. Variables - {{variableName}}
Access data from your macro configuration:
{{companyName}} โ "Acme Corporation"
{{user.firstName}} โ "John"
2. Config Values - {{@config('key')}}
Access plugin configuration values:
{{@config('appName')}} โ "My Awesome App"
{{@config('version')}} โ "1.0.0"
3. Date Functions - {{@date('format')}}
Format current date and time:
{{@date('YYYY-MM-DD')}} โ "2024-01-15"
{{@date('MMMM Do, YYYY')}} โ "January 15th, 2024"
4. Functions (Server-side only)
Transform data with custom functions:
{{@uppercase('hello')}} โ "HELLO"
{{@greet('John')}} โ "Hello, John!" (if configured)
5. Conditional Content
Show content based on conditions:
- Set up conditions in the macro block interface
- Define content for true/false scenarios
- Useful for personalized content
6. Loops
Repeat content for data collections:
- Configure collection data source
- Define template for each item
- Great for product lists, etc.
Usage Locations
โ
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
Runtime Context
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.
๐ค Contributing
Contributions are welcome! Please open issues or pull requests for bug fixes, features, or documentation improvements.

