From 56b05e26446538ac828ed856f3b77070b6530ca8 Mon Sep 17 00:00:00 2001 From: sshugsc Date: Tue, 13 Jan 2026 16:45:10 -0800 Subject: [PATCH 1/2] move sendEmail to another file to avoid circular dependency --- app/libs/email.js | 27 ++------------------------- app/libs/mailer.js | 26 ++++++++++++++++++++++++++ app/queue.js | 2 +- app/routes/report/reportUser.js | 1 - 4 files changed, 29 insertions(+), 27 deletions(-) create mode 100644 app/libs/mailer.js diff --git a/app/libs/email.js b/app/libs/email.js index 2500a5ff1..9841f5c59 100644 --- a/app/libs/email.js +++ b/app/libs/email.js @@ -1,31 +1,8 @@ -const nodemailer = require('nodemailer'); const CONFIG = require('../config'); const db = require('../models'); const {addJobToEmailQueue} = require('../queue'); -const {email, password, domain, ehost} = CONFIG.get('email'); - -const sendEmail = async (subject, text, toEmail) => { - const transporter = nodemailer.createTransport({ - host: ehost, - auth: { - user: email, - pass: password, - }, - tls: { - rejectUnauthorized: false, - }, - }); - - const mailOptions = { - from: `${email}${domain}`, - to: toEmail, - subject, - text, - }; - - return transporter.sendMail(mailOptions); -}; +const {email, domain} = CONFIG.get('email'); const getEmailList = async (triggers) => { const notifs = await db.models.notification.scope('extended').findAll({ @@ -69,4 +46,4 @@ const notifyUsers = async (subject, text, triggers) => { } }; -module.exports = {sendEmail, getEmailList, notifyUsers}; +module.exports = {getEmailList, notifyUsers}; diff --git a/app/libs/mailer.js b/app/libs/mailer.js new file mode 100644 index 000000000..99ee9304e --- /dev/null +++ b/app/libs/mailer.js @@ -0,0 +1,26 @@ +const nodemailer = require('nodemailer'); +const CONFIG = require('../config'); + +const {email, password, domain, ehost} = CONFIG.get('email'); + +const sendEmail = async ({to, subject, text}) => { + const transporter = nodemailer.createTransport({ + host: ehost, + auth: { + user: email, + pass: password, + }, + tls: { + rejectUnauthorized: false, + }, + }); + + return transporter.sendMail({ + from: `${email}${domain}`, + to, + subject, + text, + }); +}; + +module.exports = {sendEmail}; diff --git a/app/queue.js b/app/queue.js index 251a2bb5a..8644f6a97 100644 --- a/app/queue.js +++ b/app/queue.js @@ -4,7 +4,7 @@ const {graphkbGetReadonlyGroupId, graphkbAddUser} = require('./api/graphkb'); const conf = require('./config'); const createReport = require('./libs/createReport'); const db = require('./models'); -const {sendEmail} = require('./libs/email'); +const {sendEmail} = require('./libs/mailer'); const {host, port, enableQueue} = conf.get('redis_queue'); const logger = require('./log'); diff --git a/app/routes/report/reportUser.js b/app/routes/report/reportUser.js index 626053f9b..7b7bf6d32 100644 --- a/app/routes/report/reportUser.js +++ b/app/routes/report/reportUser.js @@ -153,7 +153,6 @@ router.route('/') projectId: reportProject.project_id, }, ); - logger.info('Email sent successfully'); } catch (error) { logger.error(`Email not sent successfully: ${error}`); } From 642a675f75df2d3ce704b10a5d03c55e4b85ad2c Mon Sep 17 00:00:00 2001 From: sshugsc Date: Mon, 26 Jan 2026 17:24:16 -0800 Subject: [PATCH 2/2] remove duplicate initial for nodemailer; update attributes for sendEmail function --- app/libs/email.js | 2 -- app/libs/mailer.js | 22 +++++++++++----------- app/queue.js | 18 ++++++++---------- app/routes/email/index.js | 4 ++-- 4 files changed, 21 insertions(+), 25 deletions(-) diff --git a/app/libs/email.js b/app/libs/email.js index 9841f5c59..2f7cab307 100644 --- a/app/libs/email.js +++ b/app/libs/email.js @@ -13,7 +13,6 @@ const getEmailList = async (triggers) => { for (const notif of notifs) { if (notif.user) { if (!emailList.some((el) => {return el.toEmail === notif.user.email;}) - && notif.user.email.endsWith(domain) && notif.user.allowNotifications) { emailList.push({toEmail: notif.user.email, notifId: notif.id, eventType: notif.eventType}); } @@ -21,7 +20,6 @@ const getEmailList = async (triggers) => { if (notif.userGroup) { for (const groupUser of notif.userGroup.users) { if (!emailList.some((el) => {return el.toEmail === groupUser.email;}) - && groupUser.email.endsWith(domain) && groupUser.allowNotifications) { emailList.push({toEmail: groupUser.email, notifId: notif.id, eventType: notif.eventType}); } diff --git a/app/libs/mailer.js b/app/libs/mailer.js index 99ee9304e..0a53a67e0 100644 --- a/app/libs/mailer.js +++ b/app/libs/mailer.js @@ -3,18 +3,18 @@ const CONFIG = require('../config'); const {email, password, domain, ehost} = CONFIG.get('email'); -const sendEmail = async ({to, subject, text}) => { - const transporter = nodemailer.createTransport({ - host: ehost, - auth: { - user: email, - pass: password, - }, - tls: { - rejectUnauthorized: false, - }, - }); +const transporter = nodemailer.createTransport({ + host: ehost, + auth: { + user: email, + pass: password, + }, + tls: { + rejectUnauthorized: false, + }, +}); +const sendEmail = async ({to, subject, text}) => { return transporter.sendMail({ from: `${email}${domain}`, to, diff --git a/app/queue.js b/app/queue.js index 8644f6a97..d0573c4f7 100644 --- a/app/queue.js +++ b/app/queue.js @@ -1,5 +1,4 @@ const {Queue, Worker} = require('bullmq'); -const nodemailer = require('nodemailer'); const {graphkbGetReadonlyGroupId, graphkbAddUser} = require('./api/graphkb'); const conf = require('./config'); const createReport = require('./libs/createReport'); @@ -10,13 +9,18 @@ const {host, port, enableQueue} = conf.get('redis_queue'); const logger = require('./log'); const CONFIG = require('./config'); -const {email, password, ehost, failemail} = CONFIG.get('email'); +const {failemail} = CONFIG.get('email'); let emailQueue = null; let reportQueue = null; let graphkbNewUserQueue = null; const EMAIL_REMOVE_CONFIG = { + backoff: { + type: 'exponential', + delay: 2000, + }, + delay: 5000, removeOnComplete: {age: 3600}, removeOnFail: {age: 86400}, attempts: 10, @@ -77,7 +81,7 @@ const onEmailWorkerFailed = async (job) => { try { if (failemail) { - await sendEmail('Notification failed', job.data, failemail); + await sendEmail({to: failemail, subject: 'Notification failed', text: job.data}); } } catch (error) { logger.error(`Unable to send email ${error}`); @@ -93,7 +97,6 @@ const setUpEmailWorker = (emailJobProcessor) => { }); worker.on('completed', async (job) => { await onEmailWorkerCompleted(job); - await job.remove(); logger.info(`Email job with ID ${job.id} has been completed.`); }); worker.on('failed', async (job, err) => { @@ -103,13 +106,8 @@ const setUpEmailWorker = (emailJobProcessor) => { }; const emailProcessor = async (job) => { - const transporter = nodemailer.createTransport({ - host: ehost, - auth: {user: email, pass: password}, - tls: {rejectUnauthorized: false}, - }); try { - await transporter.sendMail(job.data.mailOptions); + await sendEmail(job.data.mailOptions); } catch (err) { logger.error(JSON.stringify(job.data.mailOptions)); throw new Error(err); diff --git a/app/routes/email/index.js b/app/routes/email/index.js index e418969b3..b7c7a7124 100644 --- a/app/routes/email/index.js +++ b/app/routes/email/index.js @@ -1,6 +1,6 @@ const {StatusCodes} = require('http-status-codes'); const express = require('express'); -const {sendEmail} = require('../../libs/email'); +const {sendEmail} = require('../../libs/mailer'); const router = express.Router({mergeParams: true}); const logger = require('../../log'); @@ -10,7 +10,7 @@ const logger = require('../../log'); */ router.get('/', async (req, res) => { try { - const resp = await sendEmail('Test email', 'Test email', req.user.email); + const resp = await sendEmail({to: req.user.email, subject: 'Test email', text: 'Test email'}); logger.info({message: `Test email sent to ${req.user.email}`, response: resp.response}); return res.status(StatusCodes.OK).json({message: 'Email sent successfully'}); } catch (err) {