69 lines
2.6 KiB
TypeScript
69 lines
2.6 KiB
TypeScript
import type { Endpoint, PayloadRequest } from 'payload'
|
|
|
|
import { addDataAndFileToRequest } from 'payload'
|
|
|
|
/**
|
|
* Custom endpoint: send a test email to a given address through whatever
|
|
* transport is currently active (SMTP or Graph — mailAdapter reads the panel
|
|
* setting per send, so the test exercises the REAL path a form email would
|
|
* take). Mounted at POST /api/ipal/test-email.
|
|
*
|
|
* Admin-only: uses payload.sendEmail (server-side), and requires an
|
|
* authenticated admin user — a test-send button must never be open to the
|
|
* public (it would be an open relay / spam vector).
|
|
*
|
|
* Returns the adapter's own result so the panel can show exactly what happened,
|
|
* including the transport-specific error (SMTP auth failure, Graph 401, etc.).
|
|
*/
|
|
export const testEmailEndpoint: Endpoint = {
|
|
handler: async (req: PayloadRequest) => {
|
|
// Auth: only signed-in admins may trigger a send.
|
|
if (!req.user) {
|
|
return Response.json({ error: 'Unauthorized', ok: false }, { status: 401 })
|
|
}
|
|
|
|
await addDataAndFileToRequest(req)
|
|
const to = (req.data?.to as string | undefined)?.trim()
|
|
|
|
if (!to || !/^[^@\s]+@[^\s@][^\s.@]*\.[^\s@]+$/.test(to)) {
|
|
return Response.json(
|
|
{ error: 'Provide a valid recipient address.', ok: false },
|
|
{ status: 400 },
|
|
)
|
|
}
|
|
|
|
try {
|
|
const info = await req.payload.sendEmail({
|
|
html: '<p>This is a test message from <strong>ipal-kit</strong>. If you received it, outbound email is configured correctly.</p>',
|
|
subject: 'ipal-kit — test email',
|
|
text: 'This is a test message from ipal-kit. If you received it, outbound email is configured correctly.',
|
|
to,
|
|
})
|
|
|
|
// Payload's sendEmail resolves with the adapter's result. Our adapters
|
|
// return { sent: boolean, error?: string }; nodemailer returns info with
|
|
// messageId. Normalize to a simple ok/message for the panel.
|
|
const sent =
|
|
info && typeof info === 'object' && 'sent' in info
|
|
? (info as { sent?: boolean }).sent !== false
|
|
: true
|
|
|
|
if (!sent) {
|
|
const error = (info as { error?: string })?.error ?? 'Send failed (see server logs).'
|
|
return Response.json({ error, ok: false }, { status: 502 })
|
|
}
|
|
|
|
return Response.json({ message: `Test email sent to ${to}.`, ok: true })
|
|
} catch (err) {
|
|
const message = err instanceof Error ? err.message : String(err)
|
|
req.payload.logger.error(`[ipal] Test email failed: ${message}`)
|
|
return Response.json(
|
|
{ error: 'Send failed. Check transport settings and server logs.', ok: false },
|
|
{ status: 502 },
|
|
)
|
|
}
|
|
},
|
|
method: 'post',
|
|
path: '/ipal/test-email',
|
|
}
|