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:
2025-09-13 18:51:46 +02:00
parent 12952ad41c
commit 2deefc8eaa
4 changed files with 231 additions and 1 deletions

View File

@@ -598,6 +598,81 @@ await processEmails(payload)
await retryFailedEmails(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 ## Job Processing
The plugin automatically adds a unified email processing job to PayloadCMS: The plugin automatically adds a unified email processing job to PayloadCMS:

View File

@@ -1,6 +1,6 @@
{ {
"name": "@xtr-dev/payload-mailing", "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", "description": "Template-based email system with scheduling and job processing for PayloadCMS",
"type": "module", "type": "module",
"main": "dist/index.js", "main": "dist/index.js",

View File

@@ -11,6 +11,10 @@ export { MailingService } from './services/MailingService.js'
export { default as EmailTemplates, createEmailTemplatesCollection } from './collections/EmailTemplates.js' export { default as EmailTemplates, createEmailTemplatesCollection } from './collections/EmailTemplates.js'
export { default as Emails } from './collections/Emails.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 // Jobs are integrated into the plugin configuration
// Utility functions for developers // Utility functions for developers

View 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