{"record":{"id":"62b64c2a178bba38","repo":"danny-avila/LibreChat","slug":"failed-to-send-email-via-mailgun","errorCode":null,"errorMessage":"Failed to send email via Mailgun","messagePattern":"Failed to send email via Mailgun","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"api/server/utils/sendEmail.js","lineNumber":47,"sourceCode":"\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;\n  } catch (error) {\n    throw new Error(logAxiosError({ error, message: 'Failed to send email via Mailgun' }));\n  }\n};\n\n/**\n * Sends an email using SMTP via Nodemailer.\n *\n * @async\n * @function sendEmailViaSMTP\n * @param {Object} params - The parameters for sending the email.\n * @param {Object} params.transporterOptions - The transporter configuration options.\n * @param {Object} params.mailOptions - The email options.\n * @returns {Promise<Object>} - A promise that resolves to the info object of the sent email.\n */\nconst sendEmailViaSMTP = async ({ transporterOptions, mailOptions }) => {\n  const transporter = nodemailer.createTransport(transporterOptions);\n  return await transporter.sendMail(mailOptions);\n};\n","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/api/server/utils/sendEmail.js#L29-L65","documentation":"Thrown by sendEmailViaMailgun when the axios POST to `${mailgunHost}/v3/${mailgunDomain}/messages` fails. The underlying axios error is formatted by logAxiosError and re-thrown as a single Error whose message includes the HTTP status and Mailgun response body. Causes range from auth failure to rejected recipients to network errors.","triggerScenarios":"HTTP 401 from a wrong/revoked MAILGUN_API_KEY; 400 from a malformed recipient or bad domain; 404 when MAILGUN_DOMAIN does not match the key's account; MAILGUN_HOST pointing at the wrong region (EU vs US); TLS/DNS/network failure; rate limiting from Mailgun.","commonSituations":"Rotated the API key in the Mailgun dashboard without updating env; domain not verified in Mailgun; recipient on a suppression/bounce list; EU account using the default api.mailgun.net host.","solutions":["Read the full logAxiosError message to obtain the exact HTTP status and Mailgun error code.","For 401, regenerate the API key in Mailgun and update MAILGUN_API_KEY.","For 400/404, confirm MAILGUN_DOMAIN is a verified domain on that account and that recipients are well-formed.","For EU accounts, set MAILGUN_HOST to https://api.eu.mailgun.net.","Clear suppressions (bounces/complaints) for the recipient in the Mailgun dashboard if delivery is blocked."],"exampleFix":"// before\nawait sendEmailViaMailgun({ to, from, subject, html });\n\n// after (structured failure for the caller)\ntry {\n  await sendEmailViaMailgun({ to, from, subject, html });\n} catch (err) {\n  logger.error('Mailgun send failed:', err.message);\n  throw new Error(`Email delivery failed; please retry. (${err.message})`);\n}","handlingStrategy":"try-catch","validationCode":"if (!process.env.MAILGUN_API_KEY || !process.env.MAILGUN_DOMAIN) {\n  throw new Error('Mailgun API key and domain are required');\n}\nif (!to || !from || !subject || !html) {\n  throw new Error('to, from, subject, and html are required to send email');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await sendEmailViaMailgun({ to, from, subject, html });\n} catch (err) {\n  if (err.message.startsWith('Failed to send email via Mailgun')) {\n    logger.error('Mailgun delivery failed:', err.message);\n    throw new Error('Email delivery failed; please retry.');\n  }\n  throw err;\n}","preventionTips":["Rotate keys in Mailgun and update env together.","Verify MAILGUN_DOMAIN is an approved domain on the account.","Set MAILGUN_HOST for non-US (EU) accounts.","Clear suppressions for bounced/complained recipients before retrying."],"tags":["email","http","network","mailgun"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}