{"record":{"id":"88b4ca95103e904b","repo":"danny-avila/LibreChat","slug":"mailgun-api-key-and-domain-are-required","errorCode":null,"errorMessage":"Mailgun API key and domain are required","messagePattern":"Mailgun API key and domain are required","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"api/server/utils/sendEmail.js","lineNumber":27,"sourceCode":"/**\n * Sends an email using Mailgun API.\n *\n * @async\n * @function sendEmailViaMailgun\n * @param {Object} params - The parameters for sending the email.\n * @param {string} params.to - The recipient's email address.\n * @param {string} params.from - The sender's email address.\n * @param {string} params.subject - The subject of the email.\n * @param {string} params.html - The HTML content of the email.\n * @returns {Promise<Object>} - A promise that resolves to the response from Mailgun API.\n */\nconst sendEmailViaMailgun = async ({ to, from, subject, html }) => {\n  const mailgunApiKey = process.env.MAILGUN_API_KEY;\n  const mailgunDomain = process.env.MAILGUN_DOMAIN;\n  const mailgunHost = process.env.MAILGUN_HOST || 'https://api.mailgun.net';\n\n  if (!mailgunApiKey || !mailgunDomain) {\n    throw new Error('Mailgun API key and domain are required');\n  }\n\n  const formData = new FormData();\n  formData.append('from', from);\n  formData.append('to', to);\n  formData.append('subject', subject);\n  formData.append('html', html);\n  formData.append('o:tracking-clicks', 'no');\n\n  try {\n    const response = await axios.post(`${mailgunHost}/v3/${mailgunDomain}/messages`, formData, {\n      headers: {\n        ...formData.getHeaders(),\n        Authorization: `Basic ${Buffer.from(`api:${mailgunApiKey}`).toString('base64')}`,\n      },\n    });\n\n    return response.data;","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/api/server/utils/sendEmail.js#L9-L45","documentation":"Thrown by sendEmailViaMailgun before any network call when process.env.MAILGUN_API_KEY or process.env.MAILGUN_DOMAIN is unset. The function reads both at call time and refuses to proceed without them, since constructing the Basic-Auth header and the POST URL requires both values. It is a configuration guard, not an upstream failure.","triggerScenarios":"Email subsystem invoked (e.g. password reset, invite) in an environment where Mailgun env vars were never set; MAILGUN_API_KEY present but MAILGUN_DOMAIN missing (or vice versa); env file not loaded in the running process; deploying with a different email provider while Mailgun code paths are still active.","commonSituations":"New deploy missing secrets; switching from SMTP to Mailgun without provisioning credentials; CI environment without email env vars; a typo in the env var name.","solutions":["Set MAILGUN_API_KEY and MAILGUN_DOMAIN in the environment (and MAILGUN_HOST if using a non-default/EU host) and restart the process.","If you intend to use SMTP instead, disable/route away from the Mailgun code path.","Verify the variables are actually loaded by the process (print Object.keys(process.env).filter(k => k.startsWith('MAILGUN')) in a health check)."],"exampleFix":"// before: env missing -> throw at call time\n// after: fail fast at startup with a clear message\nif (process.env.EMAIL_SERVICE === 'mailgun') {\n  if (!process.env.MAILGUN_API_KEY || !process.env.MAILGUN_DOMAIN) {\n    throw new Error('MAILGUN_API_KEY and MAILGUN_DOMAIN must be set when EMAIL_SERVICE=mailgun');\n  }\n}","handlingStrategy":"validation","validationCode":"const mailgunApiKey = process.env.MAILGUN_API_KEY;\nconst mailgunDomain = process.env.MAILGUN_DOMAIN;\nif (!mailgunApiKey || !mailgunDomain) {\n  throw new Error('Mailgun API key and domain are required');\n}","typeGuard":"const hasMailgunConfig = () => !!process.env.MAILGUN_API_KEY && !!process.env.MAILGUN_DOMAIN;","tryCatchPattern":"try {\n  await sendEmailViaMailgun({ to, from, subject, html });\n} catch (err) {\n  if (err.message === 'Mailgun API key and domain are required') {\n    return res.status(503).json({ message: 'Email service not configured.' });\n  }\n  throw err;\n}","preventionTips":["Validate Mailgun env vars at startup, not at first send.","Keep EMAIL_SERVICE routing consistent with which provider env vars are set.","Use a secrets manager so key rotations do not leave the env half-configured."],"tags":["email","config","env","mailgun"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}