{"record":{"id":"152e945cb647ca18","repo":"nextauthjs/next-auth","slug":"malformed-mailgun-domain","errorCode":null,"errorMessage":"malformed Mailgun domain","messagePattern":"malformed Mailgun domain","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/providers/mailgun.ts","lineNumber":77,"sourceCode":"  const { region = \"US\" } = config\n  const servers = {\n    US: \"api.mailgun.net\",\n    EU: \"api.eu.mailgun.net\",\n  }\n  const apiServer = servers[region]\n\n  return {\n    id: \"mailgun\",\n    type: \"email\",\n    name: \"Mailgun\",\n    from: \"Auth.js <no-reply@authjs.dev>\",\n    maxAge: 24 * 60 * 60,\n    async sendVerificationRequest(params) {\n      const { identifier: to, provider, url, theme } = params\n      const { host } = new URL(url)\n      const domain = provider.from?.split(\"@\").at(1)\n\n      if (!domain) throw new Error(\"malformed Mailgun domain\")\n\n      const form = new FormData()\n      form.append(\"from\", `${provider.name} <${provider.from}>`)\n      form.append(\"to\", to)\n      form.append(\"subject\", `Sign in to ${host}`)\n      form.append(\"html\", html({ host, url, theme }))\n      form.append(\"text\", text({ host, url }))\n\n      const res = await fetch(`https://${apiServer}/v3/${domain}/messages`, {\n        method: \"POST\",\n        headers: {\n          Authorization: `Basic ${btoa(`api:${provider.apiKey}`)}`,\n        },\n        body: form,\n      })\n\n      if (!res.ok) throw new Error(\"Mailgun error: \" + (await res.text()))\n    },","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/nextauthjs/next-auth/blob/a1a16a5a7780488c7449feece410033f445d0b31/packages/core/src/providers/mailgun.ts#L59-L95","documentation":"The Mailgun provider derives the sending domain by splitting provider.from on \"@\" and taking the last part; if there is no \"@\" (or the part is falsy) it cannot build the Mailgun API URL and throws this Error. It guards against a malformed from address that would make the domain-based API endpoint invalid.","triggerScenarios":"sendVerificationRequest with provider.from set to a string without an \"@\" — e.g. from: \"Auth.js <no-reply>\" or from: undefined — so `provider.from?.split(\"@\").at(1)` yields undefined and `if (!domain)` throws.","commonSituations":"Copy-pasting a display name only (\"Auth.js <no-reply@authjs.dev>\" truncated), leaving from unset and relying on a default that has no address, or building the config from env vars where MAILGUN_FROM is empty or malformed.","solutions":["Set provider.from to a full email address including @, e.g. \"Auth.js <no-reply@yourdomain.com>\"","Validate the MAILGUN_FROM env var at startup (regex for user@domain)","Confirm the domain part is verified in your Mailgun account (next failure would otherwise be an API error)","Log the resolved provider config once at boot to catch empty values early"],"exampleFix":"// before\nfrom: process.env.MAILGUN_FROM || \"no-reply\" // no @ -> throw\n// after\nfrom: process.env.MAILGUN_FROM ?? \"Auth.js <no-reply@mg.yourdomain.com>\"","handlingStrategy":"validation","validationCode":"const from = process.env.MAILGUN_FROM\nif (!from || !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(from.replace(/^[^<]*<|>.*$/g, ''))) {\n  throw new Error('MAILGUN_FROM must be a full email address like \"Auth.js <no-reply@example.com>\"')\n}","typeGuard":"function hasMailgunDomain(p: { from?: string }): p is { from: string } & { domain: string } {\n  const domain = p.from?.split('@').at(1)\n  return typeof domain === 'string' && domain.length > 0\n}","tryCatchPattern":"try {\n  await sendVerificationRequest(params)\n} catch (e) {\n  if (e instanceof Error && e.message === 'malformed Mailgun domain') {\n    console.error('Mailgun provider.from must include an @domain part')\n  }\n}","preventionTips":["Always configure from as \"Name <user@domain.com>\", never a bare display name","Validate the MAILGUN_FROM env var at startup with an email regex","Ensure the domain part matches a verified Mailgun domain","Log the resolved provider config once at boot to catch empty values"],"tags":["config","email","mailgun","validation"],"backgroundTag":"invalid-email-config","analyzedSha":"a1a16a5a7780488c7449feece410033f445d0b31","analyzedAt":"2026-08-28T21:52:38.200Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}