mirror of
https://github.com/xtr-dev/payload-mailing.git
synced 2025-12-10 08:13:23 +00:00
BREAKING CHANGE: Replaced batch email processing with individual jobs per email
Changes:
- Remove sendEmailTask.ts - no longer needed as each email gets its own job
- Add processEmailJob.ts - handles individual email processing
- Update sendEmail() to automatically create individual job per email
- Add processImmediately option to sendEmail() for instant processing
- Add processJobById() utility to run specific jobs immediately
- Update job registration to use new individual job structure
- Update dev API routes to use new processImmediately pattern
- Fix all TypeScript compilation errors
Benefits:
- Better job queue visibility (one job per email)
- More granular control over individual email processing
- Easier job monitoring and failure tracking
- Maintains backward compatibility via processImmediately option
- Simpler job queue management
Migration:
- Replace sendEmailJob usage with sendEmail({ processImmediately: true })
- Individual emails now appear as separate jobs in queue
- Batch processing still available via processEmailsTask if needed
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
125 lines
3.4 KiB
TypeScript
125 lines
3.4 KiB
TypeScript
import { getPayload } from 'payload'
|
|
import config from '@payload-config'
|
|
import { sendEmail } from '@xtr-dev/payload-mailing'
|
|
|
|
export async function POST(request: Request) {
|
|
try {
|
|
const payload = await getPayload({ config })
|
|
const body = await request.json()
|
|
const { type = 'send', templateSlug, to, variables, scheduledAt, subject, html, text } = body
|
|
|
|
// Validate required fields
|
|
if (!to) {
|
|
return Response.json(
|
|
{ error: 'Recipient email address (to) is required' },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
// Validate email has either template or direct content
|
|
if (!templateSlug && (!subject || !html)) {
|
|
return Response.json(
|
|
{ error: 'Either templateSlug or both subject and html must be provided' },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
// Use the new sendEmail API
|
|
const emailOptions: any = {
|
|
data: {
|
|
to,
|
|
}
|
|
}
|
|
|
|
// Add template if provided
|
|
if (templateSlug) {
|
|
emailOptions.template = {
|
|
slug: templateSlug,
|
|
variables: variables || {}
|
|
}
|
|
} else if (subject && html) {
|
|
// Direct email without template
|
|
emailOptions.data.subject = subject
|
|
emailOptions.data.html = html
|
|
if (text) {
|
|
emailOptions.data.text = text
|
|
}
|
|
} else {
|
|
return Response.json({
|
|
error: 'Either templateSlug or subject+html must be provided'
|
|
}, { status: 400 })
|
|
}
|
|
|
|
// Add scheduling if needed
|
|
if (type === 'schedule' || scheduledAt) {
|
|
emailOptions.data.scheduledAt = scheduledAt ? new Date(scheduledAt) : new Date(Date.now() + 60000)
|
|
}
|
|
|
|
// Set processImmediately for "send now" type
|
|
const processImmediately = (type === 'send' && !scheduledAt)
|
|
emailOptions.processImmediately = processImmediately
|
|
|
|
const result = await sendEmail(payload, emailOptions)
|
|
|
|
return Response.json({
|
|
success: true,
|
|
emailId: result.id,
|
|
message: processImmediately ? 'Email sent successfully' :
|
|
scheduledAt ? 'Email scheduled successfully' :
|
|
'Email queued successfully',
|
|
status: processImmediately ? 'sent' :
|
|
scheduledAt ? 'scheduled' :
|
|
'queued'
|
|
})
|
|
} catch (error) {
|
|
console.error('Test email error:', error)
|
|
return Response.json(
|
|
{
|
|
error: 'Failed to send email',
|
|
details: error instanceof Error ? error.message : 'Unknown error'
|
|
},
|
|
{ status: 500 }
|
|
)
|
|
}
|
|
}
|
|
|
|
export async function GET() {
|
|
try {
|
|
const payload = await getPayload({ config })
|
|
|
|
// Get email templates
|
|
const { docs: templates } = await payload.find({
|
|
collection: 'email-templates' as const,
|
|
limit: 10,
|
|
})
|
|
|
|
// Get email queue status
|
|
const { docs: queuedEmails, totalDocs } = await payload.find({
|
|
collection: 'emails' as const,
|
|
limit: 10,
|
|
sort: '-createdAt',
|
|
})
|
|
|
|
return Response.json({
|
|
templates,
|
|
outbox: {
|
|
emails: queuedEmails,
|
|
total: totalDocs,
|
|
},
|
|
mailing: {
|
|
pluginActive: 'mailing' in payload && !!payload.mailing,
|
|
service: 'mailing' in payload && payload.mailing && 'service' in payload.mailing && !!payload.mailing.service,
|
|
},
|
|
})
|
|
} catch (error) {
|
|
console.error('Get mailing status error:', error)
|
|
return Response.json(
|
|
{
|
|
error: 'Failed to get mailing status',
|
|
details: error instanceof Error ? error.message : 'Unknown error'
|
|
},
|
|
{ status: 500 }
|
|
)
|
|
}
|
|
}
|