payloadcms/payload · error · APIError
Error sending email: ${statusCode}
Error message
Error sending email: ${statusCode} What it means
Thrown by the Resend email adapter when the Resend API response has no 'id' (success marker) and therefore represents an error. The adapter formats the upstream statusCode (and, if present, name + message) into an APIError thrown back to the caller. Root cause is in the Resend response: auth failure (401/403), validation (422), rate limit (429), or a Resend server error (5xx).
Source
Thrown at packages/email-resend/src/index.ts:69
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
method: 'POST',
})
const data = (await res.json()) as ResendResponse
if ('id' in data) {
return data
} else {
const statusCode = data.statusCode || res.status
let formattedError = `Error sending email: ${statusCode}`
if (data.name && data.message) {
formattedError += ` ${data.name} - ${data.message}`
}
throw new APIError(formattedError, statusCode)
}
},
})
return adapter
}
function mapPayloadEmailToResendEmail(
message: SendEmailOptions,
defaultFromAddress: string,
defaultFromName: string,
): ResendSendEmailOptions {
return {
// Required
from: mapFromAddress(message.from, defaultFromName, defaultFromAddress),
subject: message.subject ?? '',
to: mapAddresses(message.to),
View on GitHub (pinned to 00c58b35c0)
Solutions
- Inspect the formatted error (it appends name + message) for the Resend-specific reason and address it (verify domain, fix from-address, etc.).
- Confirm the RESEND_API_KEY / configured key is valid and has not been revoked.
- For 429, back off and retry with exponential backoff; for 5xx, retry after a delay.
- Verify the 'from' domain is verified in Resend and the recipient address is valid.
Defensive patterns
Strategy: retry
Validate before calling
async function resendReachable(adapter) {
// send a no-op/before-send hook check or verify domain via Resend API
} Try / catch
async function sendWithRetry(payload, msg, attempts = 3) {
for (let i = 0; i < attempts; i++) {
try { return await payload.sendEmail(msg) }
catch (err) {
const retryable = /429|5\d\d/.test(err.message) || err.statusCode >= 500
if (!retryable || i === attempts - 1) throw err
await new Promise(r => setTimeout(r, 2 ** i * 500))
}
}
} Prevention
- Keep the Resend API key in a secret manager and rotate without code changes.
- Verify sending domains in Resend before deploying.
- For bulk sends, throttle to stay under Resend rate limits.
When it happens
Trigger: Calling payload.sendEmail with the Resend adapter when the Resend API rejects the request — bad/revoked API key, invalid from-address, unverified sending domain, rate-limited, or a malformed message.
Common situations: Resend API key rotated but not updated in env; sending from an address whose domain is not verified in Resend; hitting Resend rate limits during bulk sends; transient Resend 5xx.
Related errors
- Attachment is missing filename
- Attachment is missing both content and path
- Attachment content must be a string or a buffer
- Failed to download: ${url}
- Failed to download: ${url}
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/84a23fa6518501dc.
Report an issue: GitHub.