Files
payload-mailing/dev/app/api/test-email/route.ts
Bas van den Aakster caa3686f1a Flatten email processing structure to individual jobs per email
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>
2025-09-14 20:19:07 +02:00

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 }
)
}
}