Add Claude Code GitHub Workflow
@xtr-dev/payload-mailing
📧 Template-based email system with scheduling and job processing for PayloadCMS
Features
✅ Template System: Create reusable email templates with Handlebars syntax
✅ Outbox Scheduling: Schedule emails for future delivery
✅ Job Integration: Automatic processing via PayloadCMS jobs queue
✅ Retry Failed Sends: Automatic retry mechanism for failed emails
✅ Template Variables: Dynamic content with validation
✅ Developer API: Simple methods for sending emails programmatically
Installation
npm install @xtr-dev/payload-mailing
Quick Start
1. Add the plugin to your Payload config
import { buildConfig } from 'payload/config'
import { mailingPlugin } from '@xtr-dev/payload-mailing'
export default buildConfig({
// ... your config
plugins: [
mailingPlugin({
defaultFrom: 'noreply@yoursite.com',
transport: {
host: 'smtp.gmail.com',
port: 587,
secure: false,
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS,
},
},
retryAttempts: 3,
retryDelay: 300000, // 5 minutes
queue: 'email-queue', // optional
}),
],
})
2. Send emails in your code
import { sendEmail, scheduleEmail } from '@xtr-dev/payload-mailing'
// Send immediately
const emailId = await sendEmail(payload, {
templateId: 'welcome-email',
to: 'user@example.com',
variables: {
firstName: 'John',
welcomeUrl: 'https://yoursite.com/welcome'
}
})
// Schedule for later
const scheduledId = await scheduleEmail(payload, {
templateId: 'reminder-email',
to: 'user@example.com',
scheduledAt: new Date(Date.now() + 24 * 60 * 60 * 1000), // 24 hours
variables: {
eventName: 'Product Launch',
eventDate: new Date('2024-01-15')
}
})
Configuration
Plugin Options
interface MailingPluginConfig {
collections?: {
templates?: string // default: 'email-templates'
outbox?: string // default: 'email-outbox'
}
defaultFrom?: string
transport?: Transporter | MailingTransportConfig
queue?: string // default: 'default'
retryAttempts?: number // default: 3
retryDelay?: number // default: 300000 (5 minutes)
}
Transport Configuration
You can provide either a Nodemailer transporter instance or configuration:
// Using configuration object
{
transport: {
host: 'smtp.gmail.com',
port: 587,
secure: false,
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS,
},
}
}
// Or using a transporter instance
import nodemailer from 'nodemailer'
{
transport: nodemailer.createTransporter({
// your config
})
}
Creating Email Templates
- Go to your Payload admin panel
- Navigate to Mailing > Email Templates
- Create a new template with:
- Name: Descriptive name for the template
- Subject: Email subject (supports Handlebars)
- HTML Template: HTML content with Handlebars syntax
- Text Template: Plain text version (optional)
- Variables: Define available variables
Template Example
Subject: Welcome to {{siteName}}, {{firstName}}!
HTML Template:
<h1>Welcome {{firstName}}!</h1>
<p>Thanks for joining {{siteName}}. We're excited to have you!</p>
{{#if isPremium}}
<p><strong>Premium Benefits:</strong></p>
<ul>
<li>Priority support</li>
<li>Advanced features</li>
<li>Monthly reports</li>
</ul>
{{/if}}
<p>Your account was created on {{formatDate createdAt 'long'}}.</p>
<p>Visit your dashboard: <a href="{{dashboardUrl}}">Get Started</a></p>
<hr>
<p>Best regards,<br>The {{siteName}} Team</p>
Handlebars Helpers
The plugin includes several built-in helpers:
{{formatDate date 'short'}}- Format dates (short, long, or default){{formatCurrency amount 'USD'}}- Format currency{{capitalize string}}- Capitalize first letter{{#ifEquals value1 value2}}...{{/ifEquals}}- Conditional equality
API Methods
sendEmail(payload, options)
Send an email immediately:
const emailId = await sendEmail(payload, {
templateId: 'order-confirmation', // optional
to: 'customer@example.com',
cc: 'manager@example.com', // optional
bcc: 'archive@example.com', // optional
from: 'orders@yoursite.com', // optional, uses default
replyTo: 'support@yoursite.com', // optional
subject: 'Custom subject', // required if no template
html: '<h1>Custom HTML</h1>', // required if no template
text: 'Custom text version', // optional
variables: { // template variables
orderNumber: '12345',
customerName: 'John Doe'
},
priority: 1 // optional, 1-10 (1 = highest)
})
scheduleEmail(payload, options)
Schedule an email for later delivery:
const emailId = await scheduleEmail(payload, {
templateId: 'newsletter',
to: ['user1@example.com', 'user2@example.com'],
scheduledAt: new Date('2024-01-15T10:00:00Z'),
variables: {
month: 'January',
highlights: ['Feature A', 'Feature B']
}
})
processOutbox(payload)
Manually process pending emails:
await processOutbox(payload)
retryFailedEmails(payload)
Manually retry failed emails:
await retryFailedEmails(payload)
Job Processing
The plugin automatically processes emails using PayloadCMS jobs:
- Outbox Processing: Every 5 minutes
- Failed Email Retry: Every 30 minutes
Ensure you have jobs configured in your Payload config:
export default buildConfig({
jobs: {
// Configure your job processing
tasks: [],
// ... other job config
},
})
Email Status Tracking
All emails are stored in the outbox collection with these statuses:
pending- Waiting to be sentprocessing- Currently being sentsent- Successfully deliveredfailed- Failed to send (will retry if attempts < retryAttempts)
Monitoring
Check the Mailing > Email Outbox collection in your admin panel to:
- View email delivery status
- See error messages for failed sends
- Track retry attempts
- Monitor scheduled emails
Environment Variables
# Email configuration
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USER=your-email@gmail.com
EMAIL_PASS=your-app-password
EMAIL_FROM=noreply@yoursite.com
TypeScript Support
The plugin includes full TypeScript definitions. Import types as needed:
import {
MailingPluginConfig,
SendEmailOptions,
EmailTemplate,
OutboxEmail
} from '@xtr-dev/payload-mailing'
License
MIT
Contributing
Issues and pull requests welcome at GitHub repository