different-ai/openwork · error · EmailSendError

nodemailer_rejected

nodemailer_rejected

Error message

[${input.template}] email for ${input.recipient} failed: ${input.reason}${input.detail ? ` (${input.detail})` : ""}

What it means

The Nodemailer SMTP transport wraps any exception thrown by transporter.sendMail in EmailSendError with reason "nodemailer_rejected", preserving the underlying message (SMTP error, auth failure, connection error) in detail. It means the SMTP delivery itself failed rather than an API-level rejection.

Source

Thrown at packages/email/src/send-email.ts:196

      auth: smtp.user
        ? {
            user: smtp.user,
            pass: smtp.pass,
          }
        : undefined,
    })

    await transporter.sendMail({
      from,
      to: input.to,
      subject: input.subject,
      replyTo: input.replyTo,
      html: input.html,
      text: input.text,
    })
  } catch (error) {
    const message = error instanceof Error ? error.message : "Unknown error"
    throw new EmailSendError({ template: input.template, reason: "nodemailer_rejected", recipient: input.to, detail: message })
  }
}

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Read detail in the thrown EmailSendError for the exact SMTP error code/message
  2. Verify SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS env values and that the account is active
  3. Confirm the host allows outbound traffic on the configured SMTP port (many clouds block 25; use 587 with STARTTLS)
  4. If the error is 5xx auth/login failure, reset credentials or enable an app password
  5. Retry for transient 4xx SMTP responses; verify the recipient address for 550-class rejections

Example fix

// before
transporter = nodemailer.createTransport({ host: 'smtp.gmail.com', port: 25 }) // blocked + no auth
// after
transporter = nodemailer.createTransport({ host: 'smtp.gmail.com', port: 587, secure: false, auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS } })
Defensive patterns

Strategy: try-catch

Validate before calling

function assertSmtpConfig(env) {
  for (const key of ['SMTP_HOST', 'SMTP_PORT', 'SMTP_USER', 'SMTP_PASS']) {
    if (!env[key]) throw new Error(`Missing ${key} — nodemailer sends will fail`);
  }
  const port = Number(env.SMTP_PORT);
  if (port !== 587 && port !== 465) console.warn(`Unusual SMTP port ${port}; many clouds block 25`);
}

Try / catch

try {
  await sendEmail({ template, to })
} catch (e) {
  if (e instanceof EmailSendError && e.reason === 'nodemailer_rejected') {
    console.error(`SMTP send failed: ${e.detail}`) // inspect SMTP code in detail
  } else throw e
}

Prevention

When it happens

Trigger: sendEmail routed to the Nodemailer provider and transporter.sendMail throws — SMTP connection refused, bad credentials, rejected recipient, TLS failure, or timeout.

Common situations: Wrong SMTP host/port or missing credentials in env (SMTP_HOST/SMTP_USER/SMTP_PASS); provider blocking port 25/587 from cloud hosts; self-signed or expired TLS certificates; recipient address rejected by the mail server; rate limits on the SMTP account.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/ff882b4f881d4a03. Report an issue: GitHub.