| const path = require('path'); |
| const axios = require('axios'); |
| const FormData = require('form-data'); |
| const nodemailer = require('nodemailer'); |
| const handlebars = require('handlebars'); |
| const { logger } = require('@librechat/data-schemas'); |
| const { logAxiosError, isEnabled, readFileAsString } = require('@librechat/api'); |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| const sendEmailViaMailgun = async ({ to, from, subject, html }) => { |
| const mailgunApiKey = process.env.MAILGUN_API_KEY; |
| const mailgunDomain = process.env.MAILGUN_DOMAIN; |
| const mailgunHost = process.env.MAILGUN_HOST || 'https://api.mailgun.net'; |
|
|
| if (!mailgunApiKey || !mailgunDomain) { |
| throw new Error('Mailgun API key and domain are required'); |
| } |
|
|
| const formData = new FormData(); |
| formData.append('from', from); |
| formData.append('to', to); |
| formData.append('subject', subject); |
| formData.append('html', html); |
| formData.append('o:tracking-clicks', 'no'); |
|
|
| try { |
| const response = await axios.post(`${mailgunHost}/v3/${mailgunDomain}/messages`, formData, { |
| headers: { |
| ...formData.getHeaders(), |
| Authorization: `Basic ${Buffer.from(`api:${mailgunApiKey}`).toString('base64')}`, |
| }, |
| }); |
|
|
| return response.data; |
| } catch (error) { |
| throw new Error(logAxiosError({ error, message: 'Failed to send email via Mailgun' })); |
| } |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| const sendEmailViaSMTP = async ({ transporterOptions, mailOptions }) => { |
| const transporter = nodemailer.createTransport(transporterOptions); |
| return await transporter.sendMail(mailOptions); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| const sendEmail = async ({ email, subject, payload, template, throwError = true }) => { |
| try { |
| const { content: source } = await readFileAsString(path.join(__dirname, 'emails', template)); |
| const compiledTemplate = handlebars.compile(source); |
| const html = compiledTemplate(payload); |
|
|
| |
| const fromName = process.env.EMAIL_FROM_NAME || process.env.APP_TITLE; |
| const fromEmail = process.env.EMAIL_FROM; |
| const fromAddress = `"${fromName}" <${fromEmail}>`; |
| const toAddress = `"${payload.name}" <${email}>`; |
|
|
| |
| if (process.env.MAILGUN_API_KEY && process.env.MAILGUN_DOMAIN) { |
| logger.debug('[sendEmail] Using Mailgun provider'); |
| return await sendEmailViaMailgun({ |
| from: fromAddress, |
| to: toAddress, |
| subject: subject, |
| html: html, |
| }); |
| } |
|
|
| |
| logger.debug('[sendEmail] Using SMTP provider'); |
| const transporterOptions = { |
| |
| secure: process.env.EMAIL_ENCRYPTION === 'tls', |
| |
| requireTls: process.env.EMAIL_ENCRYPTION === 'starttls', |
| tls: { |
| |
| rejectUnauthorized: !isEnabled(process.env.EMAIL_ALLOW_SELFSIGNED), |
| }, |
| auth: { |
| user: process.env.EMAIL_USERNAME, |
| pass: process.env.EMAIL_PASSWORD, |
| }, |
| }; |
|
|
| if (process.env.EMAIL_ENCRYPTION_HOSTNAME) { |
| |
| transporterOptions.tls.servername = process.env.EMAIL_ENCRYPTION_HOSTNAME; |
| } |
|
|
| |
| if (process.env.EMAIL_SERVICE) { |
| transporterOptions.service = process.env.EMAIL_SERVICE; |
| } else { |
| transporterOptions.host = process.env.EMAIL_HOST; |
| transporterOptions.port = process.env.EMAIL_PORT ?? 25; |
| } |
|
|
| const mailOptions = { |
| |
| from: fromAddress, |
| to: toAddress, |
| envelope: { |
| |
| |
| from: fromEmail, |
| to: email, |
| }, |
| subject: subject, |
| html: html, |
| }; |
|
|
| return await sendEmailViaSMTP({ transporterOptions, mailOptions }); |
| } catch (error) { |
| if (throwError) { |
| throw error; |
| } |
| logger.error('[sendEmail]', error); |
| return error; |
| } |
| }; |
|
|
| module.exports = sendEmail; |
|
|