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

  1. Inspect the formatted error (it appends name + message) for the Resend-specific reason and address it (verify domain, fix from-address, etc.).
  2. Confirm the RESEND_API_KEY / configured key is valid and has not been revoked.
  3. For 429, back off and retry with exponential backoff; for 5xx, retry after a delay.
  4. 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

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


AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12). Data as JSON: /api/errors/84a23fa6518501dc. Report an issue: GitHub.