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

@fareszedney/payload-plugin-email-templates

v1.4.0

Published

Adds a configurable email-templates collection and reusable email rendering, syntax-validation, and sending utilities to a Payload 3 project.

Readme

Payload Email Templates Plugin

Adds a configurable email-templates collection and reusable email rendering, syntax-validation, and sending utilities to a Payload 3 project.

The plugin provides the template collection and sendTemplatedEmail helper. It does not send email automatically: your Payload project must configure an email adapter and call the helper from server-side application code, such as a hook or endpoint.

Install

Install this package and a Payload email adapter in your Payload project. For SMTP, the Nodemailer adapter is one option:

pnpm add @fareszedney/payload-plugin-email-templates @payloadcms/email-nodemailer

Configure Payload

Register the plugin in your Payload config and configure an email adapter. purposes defines the template types your application will use. The variableResolver paths are also shown to the template designer.

import { buildConfig } from 'payload'
import { nodemailerAdapter } from '@payloadcms/email-nodemailer'
import { emailTemplatesPlugin } from '@fareszedney/payload-plugin-email-templates'

export default buildConfig({
  // Keep your existing collections, database, and other config here.
  email: nodemailerAdapter({
    defaultFromAddress: process.env.SMTP_EMAIL_FROM_ADDRESS!,
    defaultFromName: 'Example App',
    transportOptions: {
      host: process.env.SMTP_HOST,
      port: Number(process.env.SMTP_PORT || 587),
      auth: {
        user: process.env.SMTP_USER,
        pass: process.env.SMTP_PASSWORD,
      },
    },
  }),
  plugins: [
    emailTemplatesPlugin({
      purposes: [{ label: 'Receipt', value: 'receipts' }],
      variableResolver: (purpose) =>
        purpose === 'receipts' ? ['customer.name', 'order.number'] : [],
    }),
  ],
})

Set the SMTP environment variables for your provider. The helper passes SMTP_EMAIL_FROM_ADDRESS as the message sender as well, so configure it to a valid sender address for your email provider. You can use another Payload email adapter instead; the adapter is configured by the consuming project, not by this plugin.

Create a template

Start Payload and open the Email Templates collection in the admin panel. Create and enable a template with the Receipt purpose. Design its content using the available variable paths, for example customer.name and order.number. The purpose value must match the value used in your call to sendTemplatedEmail.

By default, templates can have static attachments from the media collection and an option to attach a generated document. You can change the collection slug, access rules, localization, attachment options, and other behavior using the plugin options.

Send a templated email

Call the helper from server-side code where you have a Payload request, such as an afterChange hook. The example below looks up the enabled receipt template and sends it after an order is created:

import type { CollectionAfterChangeHook } from 'payload'
import { sendTemplatedEmail } from '@fareszedney/payload-plugin-email-templates'

export const sendReceiptEmail: CollectionAfterChangeHook = async ({
  doc,
  req,
  operation,
}) => {
  if (operation !== 'create' || !doc.email) return doc

  const { docs } = await req.payload.find({
    collection: 'email-templates',
    where: {
      and: [
        { purpose: { equals: 'receipts' } },
        { enabled: { equals: true } },
      ],
    },
    limit: 1,
  })
  const template = docs[0]

  if (template) {
    await sendTemplatedEmail({
      req,
      template,
      expectedPurpose: 'receipts',
      to: doc.email,
      variables: {
        customer: { name: doc.customerName },
        order: { number: doc.number },
      },
      fallbackSubject: `Receipt for order ${doc.number}`,
    })
  }

  return doc
}

Add the hook to the relevant collection in your Payload config. Adapt the collection slug, recipient field, and variables to your generated Payload types and application schema.

sendTemplatedEmail renders the subject and HTML using the supplied variables, and sends through req.payload.sendEmail. cc and bcc are optional. It returns true when it sends and false when sending is skipped, for example when the template is disabled, its purpose does not match, its HTML is empty, or the recipient address is invalid.

Send a test email from the designer

The bundled designer includes a recipient field and Send test email button. By default, the plugin registers an authenticated POST /api/email-templates/test collection endpoint (under the Payload API route prefix) that sends the current designer HTML through the consuming project's Payload email adapter. The button appears only when the plugin endpoint is enabled.

Any authenticated user can send a test email by default. Because this can send email to an arbitrary address, restrict it to trusted administrators with testEmailAccess:

emailTemplatesPlugin({
  purposes: [{ label: 'Receipt', value: 'receipts' }],
  testEmailAccess: ({ req }) => req.user?.role === 'admin',
})

Adapt the role check to your user schema and access policy. If your application does not want a plugin-managed test endpoint, set testEmailEndpoint: false and implement the test-send flow in your own project. You can customize the collection endpoint suffix with a slash-prefixed testEmailEndpoint value; for example, /preview registers POST /api/email-templates/preview.

Attachments

Static attachments are selected on the template and loaded from the configured media collection. For relative media URLs, set PAYLOAD_PUBLIC_SERVER_URL to the base URL from which the Payload server can fetch those files.

To attach a generated file, provide a generatedAttachments callback. It is called only when the template's Attach Generated Document option is enabled:

await sendTemplatedEmail({
  req,
  template,
  expectedPurpose: 'receipts',
  to: customer.email,
  variables: { customer: { name: customer.name } },
  fallbackSubject: 'Your receipt',
  generatedAttachments: async () => [
    {
      filename: 'receipt.pdf',
      content: receiptPdfBuffer,
      contentType: 'application/pdf',
    },
  ],
})

The consuming project is responsible for generating that file and returning the attachment data.

Plugin options

  • purposes (required): purpose labels and values available to templates. At least one purpose is required.
  • variableResolver: variable paths or variable definitions exposed to the designer for each purpose.
  • variableDocs: richer variable documentation for the designer; takes precedence over variableResolver when both are provided.
  • collectionSlug, mediaCollection, labels, adminGroup: customize the collection and its admin presentation.
  • access: access control for the templates collection. Define permissions appropriate to your project.
  • localized: enable localization for template fields (defaults to true).
  • enableAttachments and enableGeneratedDocAttachment: enable their respective template fields (both default to true).
  • disabled: hide the collection and prevent sendTemplatedEmail from sending (defaults to false).
  • fieldComponent: replace the bundled admin template designer with a custom field component.
  • testEmailEndpoint: set the collection-relative test endpoint suffix (defaults to /test) or false to disable the endpoint and designer button.
  • testEmailAccess: authorize test sends; by default, any authenticated user may send one.

variableResolver and variableDocs make variable descriptions available to the admin designer; the consuming application remains responsible for passing the corresponding values to sendTemplatedEmail. Consumer-owned permissions, notification orchestration, and generated-document creation remain in the consumer project.

Development

Run pnpm build in this package to produce the published dist entry points.