mirror of
https://github.com/xtr-dev/payload-mailing.git
synced 2025-12-10 00:03:23 +00:00
✨ FEATURE: Add PayloadCMS task for queuing template emails
- Add sendTemplateEmailTask with comprehensive input schema - Support template rendering, email parsing, and scheduling - Include TypeScript interface SendTemplateEmailInput for type safety - Add task to exports for easy import and usage - Support custom email collection fields via extensible input - Add comprehensive documentation with usage examples Users can now: ✅ Import and add task to their Payload jobs configuration ✅ Queue emails programmatically via payload.jobs.queue() ✅ Use admin panel form interface for manual email queuing ✅ Get full TypeScript support with proper input types ✅ Extend with custom fields from their email collection Example usage: ```typescript import { sendTemplateEmailTask } from '@xtr-dev/payload-mailing' // Add to Payload config export default buildConfig({ jobs: { tasks: [sendTemplateEmailTask] } }) // Queue from code await payload.jobs.queue({ task: 'send-template-email', input: { templateSlug: 'welcome', to: ['user@example.com'], variables: { name: 'John' } } }) ``` 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
75
README.md
75
README.md
@@ -598,6 +598,81 @@ await processEmails(payload)
|
||||
await retryFailedEmails(payload)
|
||||
```
|
||||
|
||||
## PayloadCMS Task Integration
|
||||
|
||||
The plugin provides a ready-to-use PayloadCMS task for queuing template emails:
|
||||
|
||||
### 1. Add the task to your Payload config
|
||||
|
||||
```typescript
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { sendTemplateEmailTask } from '@xtr-dev/payload-mailing'
|
||||
|
||||
export default buildConfig({
|
||||
// ... your config
|
||||
jobs: {
|
||||
tasks: [
|
||||
sendTemplateEmailTask,
|
||||
// ... your other tasks
|
||||
]
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 2. Queue emails from your code
|
||||
|
||||
```typescript
|
||||
import type { SendTemplateEmailInput } from '@xtr-dev/payload-mailing'
|
||||
|
||||
// Queue a template email
|
||||
const result = await payload.jobs.queue({
|
||||
task: 'send-template-email',
|
||||
input: {
|
||||
templateSlug: 'welcome-email',
|
||||
to: ['user@example.com'],
|
||||
cc: ['manager@example.com'],
|
||||
variables: {
|
||||
firstName: 'John',
|
||||
activationUrl: 'https://example.com/activate/123'
|
||||
},
|
||||
priority: 1,
|
||||
// Add any custom fields from your email collection
|
||||
customField: 'value'
|
||||
} as SendTemplateEmailInput
|
||||
})
|
||||
|
||||
// Queue a scheduled email
|
||||
await payload.jobs.queue({
|
||||
task: 'send-template-email',
|
||||
input: {
|
||||
templateSlug: 'reminder-email',
|
||||
to: ['user@example.com'],
|
||||
variables: { eventName: 'Product Launch' },
|
||||
scheduledAt: new Date('2024-01-15T10:00:00Z').toISOString(),
|
||||
priority: 3
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 3. Use in admin panel workflows
|
||||
|
||||
The task can also be triggered from the Payload admin panel with a user-friendly form interface that includes:
|
||||
- Template slug selection
|
||||
- Email recipients (to, cc, bcc)
|
||||
- Template variables as JSON
|
||||
- Optional scheduling
|
||||
- Priority setting
|
||||
- Any custom fields you've added to your email collection
|
||||
|
||||
### Task Benefits
|
||||
|
||||
- ✅ **Easy Integration**: Just add to your tasks array
|
||||
- ✅ **Type Safety**: Full TypeScript support with `SendTemplateEmailInput`
|
||||
- ✅ **Admin UI**: Ready-to-use form interface
|
||||
- ✅ **Flexible**: Supports all your custom email collection fields
|
||||
- ✅ **Error Handling**: Comprehensive error reporting
|
||||
- ✅ **Queue Management**: Leverage Payload's job queue system
|
||||
|
||||
## Job Processing
|
||||
|
||||
The plugin automatically adds a unified email processing job to PayloadCMS:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@xtr-dev/payload-mailing",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.3",
|
||||
"description": "Template-based email system with scheduling and job processing for PayloadCMS",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
|
||||
@@ -11,6 +11,10 @@ export { MailingService } from './services/MailingService.js'
|
||||
export { default as EmailTemplates, createEmailTemplatesCollection } from './collections/EmailTemplates.js'
|
||||
export { default as Emails } from './collections/Emails.js'
|
||||
|
||||
// Tasks
|
||||
export { sendTemplateEmailTask, default as sendTemplateEmailTaskDefault } from './tasks/sendTemplateEmailTask.js'
|
||||
export type { SendTemplateEmailInput } from './tasks/sendTemplateEmailTask.js'
|
||||
|
||||
// Jobs are integrated into the plugin configuration
|
||||
|
||||
// Utility functions for developers
|
||||
|
||||
151
src/tasks/sendTemplateEmailTask.ts
Normal file
151
src/tasks/sendTemplateEmailTask.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
import { renderTemplate } from '../utils/helpers.js'
|
||||
|
||||
export interface SendTemplateEmailInput {
|
||||
templateSlug: string
|
||||
to: string | string[]
|
||||
cc?: string | string[]
|
||||
bcc?: string | string[]
|
||||
variables?: Record<string, any>
|
||||
scheduledAt?: string // ISO date string
|
||||
priority?: number
|
||||
// Allow any additional fields that users might have in their email collection
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export const sendTemplateEmailTask = {
|
||||
slug: 'send-template-email',
|
||||
label: 'Send Template Email',
|
||||
inputSchema: [
|
||||
{
|
||||
name: 'templateSlug',
|
||||
type: 'text' as const,
|
||||
required: true,
|
||||
label: 'Template Slug',
|
||||
admin: {
|
||||
description: 'The slug of the email template to render'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'to',
|
||||
type: 'text' as const,
|
||||
required: true,
|
||||
label: 'To (Email Recipients)',
|
||||
admin: {
|
||||
description: 'Comma-separated list of email addresses'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'cc',
|
||||
type: 'text' as const,
|
||||
label: 'CC (Carbon Copy)',
|
||||
admin: {
|
||||
description: 'Optional comma-separated list of CC email addresses'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'bcc',
|
||||
type: 'text' as const,
|
||||
label: 'BCC (Blind Carbon Copy)',
|
||||
admin: {
|
||||
description: 'Optional comma-separated list of BCC email addresses'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'variables',
|
||||
type: 'json' as const,
|
||||
label: 'Template Variables',
|
||||
admin: {
|
||||
description: 'JSON object with variables for template rendering'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'scheduledAt',
|
||||
type: 'date' as const,
|
||||
label: 'Schedule For',
|
||||
admin: {
|
||||
description: 'Optional date/time to schedule email for future delivery'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'priority',
|
||||
type: 'number' as const,
|
||||
label: 'Priority',
|
||||
min: 1,
|
||||
max: 10,
|
||||
admin: {
|
||||
description: 'Email priority (1 = highest, 10 = lowest)'
|
||||
}
|
||||
}
|
||||
],
|
||||
handler: async ({ input, payload }: any) => {
|
||||
// Cast input to our expected type
|
||||
const taskInput = input as SendTemplateEmailInput
|
||||
|
||||
try {
|
||||
// Render the template
|
||||
const { html, text, subject } = await renderTemplate(
|
||||
payload,
|
||||
taskInput.templateSlug,
|
||||
taskInput.variables || {}
|
||||
)
|
||||
|
||||
// Parse email addresses
|
||||
const parseEmails = (emails: string | string[] | undefined): string[] | undefined => {
|
||||
if (!emails) return undefined
|
||||
if (Array.isArray(emails)) return emails
|
||||
return emails.split(',').map(email => email.trim()).filter(Boolean)
|
||||
}
|
||||
|
||||
// Prepare email data
|
||||
const emailData: any = {
|
||||
to: parseEmails(taskInput.to),
|
||||
cc: parseEmails(taskInput.cc),
|
||||
bcc: parseEmails(taskInput.bcc),
|
||||
subject,
|
||||
html,
|
||||
text,
|
||||
priority: taskInput.priority || 5,
|
||||
}
|
||||
|
||||
// Add scheduled date if provided
|
||||
if (taskInput.scheduledAt) {
|
||||
emailData.scheduledAt = new Date(taskInput.scheduledAt).toISOString()
|
||||
}
|
||||
|
||||
// Add any additional fields from input (excluding the ones we've already handled)
|
||||
const handledFields = ['templateSlug', 'to', 'cc', 'bcc', 'variables', 'scheduledAt', 'priority']
|
||||
Object.keys(taskInput).forEach(key => {
|
||||
if (!handledFields.includes(key)) {
|
||||
emailData[key] = taskInput[key]
|
||||
}
|
||||
})
|
||||
|
||||
// Create the email in the collection
|
||||
const email = await payload.create({
|
||||
collection: 'emails', // Default collection name
|
||||
data: emailData
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
emailId: email.id,
|
||||
message: `Email queued successfully with ID: ${email.id}`,
|
||||
templateSlug: taskInput.templateSlug,
|
||||
recipients: emailData.to?.length || 0,
|
||||
scheduledAt: emailData.scheduledAt || null
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: errorMessage,
|
||||
templateSlug: taskInput.templateSlug,
|
||||
message: `Failed to queue email: ${errorMessage}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default sendTemplateEmailTask
|
||||
Reference in New Issue
Block a user