nextauthjs/next-auth · error · AuthError

Nodemailer requires a `server` configuration

Error message

Nodemailer requires a `server` configuration

What it means

An AuthError thrown at provider construction time: Nodemailer(config) requires a `server` property (SMTP transport options for nodemailer) to create the email transport. Without it, the library cannot build a transporter, so it fails immediately rather than at send time. This is purely a configuration error thrown when the provider is created.

Source

Thrown at packages/core/src/providers/nodemailer.ts:55

    expires: Date
    provider: NodemailerConfig
    token: string
    theme: Theme
    request: Request
  }) => Awaitable<void>
  options?: NodemailerUserConfig
}

export type NodemailerUserConfig = Omit<
  Partial<NodemailerConfig>,
  "options" | "type"
>

export default function Nodemailer(
  config: NodemailerUserConfig
): NodemailerConfig {
  if (!config.server)
    throw new AuthError("Nodemailer requires a `server` configuration")

  return {
    id: "nodemailer",
    type: "email",
    name: "Nodemailer",
    server: { host: "localhost", port: 25, auth: { user: "", pass: "" } },
    from: "Auth.js <no-reply@authjs.dev>",
    maxAge: 24 * 60 * 60,
    async sendVerificationRequest(params) {
      const { identifier, url, provider, theme } = params
      const { host } = new URL(url)
      const transport = createTransport(provider.server)
      const result = await transport.sendMail({
        to: identifier,
        from: provider.from,
        subject: `Sign in to ${host}`,
        text: text({ url, host }),
        html: html({ url, host, theme }),

View on GitHub (pinned to a1a16a5a77)

Solutions

  1. Pass server: { host, port, auth: { user, pass } } (or a nodemailer SMTP URL string) to Nodemailer()
  2. Ensure the EMAIL_SERVER env var is defined in the target environment and parsed before constructing the provider
  3. Log/validate the email config at startup so missing server values fail fast with a clear message
  4. If using a JSON env var, wrap JSON.parse in a try/catch and assert the result has host/port

Example fix

// before
Nodemailer({ from: "no-reply@example.com" }) // no server -> AuthError
// after
import Nodemailer from "@auth/core/providers/nodemailer"
Nodemailer({
  server: {
    host: process.env.EMAIL_SERVER_HOST,
    port: Number(process.env.EMAIL_SERVER_PORT),
    auth: { user: process.env.EMAIL_SERVER_USER, pass: process.env.EMAIL_SERVER_PASS },
  },
  from: "no-reply@example.com",
})
Defensive patterns

Strategy: validation

Validate before calling

const server = process.env.EMAIL_SERVER
  ? JSON.parse(process.env.EMAIL_SERVER)
  : undefined
if (!server?.host) throw new Error('EMAIL_SERVER must define at least { host, port, auth }')

Type guard

function hasSmtpServer(c: { server?: { host?: string; port?: number } }): c is { server: { host: string; port: number } } {
  return typeof c.server?.host === 'string' && typeof c.server?.port === 'number'
}

Try / catch

let provider
try {
  provider = Nodemailer(config)
} catch (e) {
  if (e instanceof AuthError && e.message.includes('requires a `server` configuration')) {
    console.error('Nodemailer misconfigured: EMAIL_SERVER missing at startup')
    throw e // fail fast — email sign-in cannot work without SMTP
  }
  throw e
}

Prevention

When it happens

Trigger: Calling Nodemailer({}) or Nodemailer({ from: ... }) without a server field — e.g. process.env.EMAIL_SERVER is undefined so JSON.parse yields nothing, or the developer simply omitted server. The guard `if (!config.server)` throws before returning the provider config.

Common situations: Missing EMAIL_SERVER env var in the deployment environment (works locally, fails in prod); forgetting to JSON.stringify the SMTP URL into an env var; renaming config keys during an upgrade from NextAuth v4 to Auth.js v5 where defaults changed.

Related errors


AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28). Data as JSON: /api/errors/3ce118e6177e90ce. Report an issue: GitHub.