const path = require("path"); require("dotenv").config({ path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) }); const axios = require("axios"); const InstanceManager = require("../utils/instanceMgr").default; const logger = require("../utils/logger"); const client = require("../graphql-client/graphql-client").client; const queries = require("../graphql-client/queries"); const { isObject } = require("lodash"); const generateEmailTemplate = require("./generateTemplate"); const mailer = require("./mailer"); // Get the image from the URL and return it as a base64 string const getImage = async (imageUrl) => { let image = await axios.get(imageUrl, { responseType: "arraybuffer" }); let raw = Buffer.from(image.data).toString("base64"); return "data:" + image.headers["content-type"] + ";base64," + raw; }; // Log the email in the database const logEmail = async (req, email) => { try { await client.request(queries.INSERT_EMAIL_AUDIT, { email: { to: email.to, cc: email.cc, subject: email.subject, bodyshopid: req.body.bodyshopid, useremail: req.user.email, contents: req.body.html, jobid: req.body.jobid, sesmessageid: email.messageId, status: "Sent" } }); } catch (error) { logger.log("email-log-error", "error", req?.user?.email, null, { from: `${req.body.from.name} <${req.body.from.address}>`, to: req?.body?.to, cc: req?.body?.cc, subject: req?.body?.subject, email // info, }); } }; const sendServerEmail = async ({ subject, text }) => { if (process.env.NODE_ENV === undefined) return; try { mailer.sendMail( { from: InstanceManager({ imex: `ImEX Online API - ${process.env.NODE_ENV} `, rome: `Rome Online API - ${process.env.NODE_ENV} ` }), to: ["patrick@imexsystems.ca", "support@thinkimex.com"], subject: subject, text: text, ses: { // optional extra arguments for SendRawEmail Tags: [ { Name: "tag_name", Value: "tag_value" } ] } }, (err, info) => { logger.log("server-email-failure", err ? "error" : "debug", null, null, { message: err || info }); } ); } catch (error) { logger.log("server-email-failure", "error", null, null, { error }); } }; const sendTaskEmail = async ({ to, subject, type = "text", html, text, attachments }) => { try { mailer.sendMail( { from: InstanceManager({ imex: `ImEX Online `, rome: `Rome Online ` }), to: to, subject: subject, ...(type === "text" ? { text } : { html }), attachments: attachments || null }, (err, info) => { // (message, type, user, record, meta logger.log("server-email", err ? "error" : "debug", null, null, { message: err || info }); } ); } catch (error) { logger.log("server-email-failure", "error", null, null, { error }); } }; // Send an email const sendEmail = async (req, res) => { logger.log("send-email", "DEBUG", req.user.email, null, { from: `${req.body.from.name} <${req.body.from.address}>`, replyTo: req.body.ReplyTo.Email, to: req.body.to, cc: req.body.cc, subject: req.body.subject, templateStrings: req.body.templateStrings }); let downloadedMedia = []; if (req.body.media && req.body.media.length > 0) { downloadedMedia = await Promise.all( req.body.media.map((m) => { try { return getImage(m); } catch (error) { logger.log("send-email-error", "ERROR", req.user.email, null, { from: `${req.body.from.name} <${req.body.from.address}>`, replyTo: req.body.ReplyTo.Email, to: req.body.to, cc: req.body.cc, subject: req.body.subject, templateStrings: req.body.templateStrings, error }); } }) ); } mailer.sendMail( { from: `${req.body.from.name} <${req.body.from.address}>`, replyTo: req.body.ReplyTo.Email, to: req.body.to, cc: req.body.cc, subject: req.body.subject, attachments: [ ...((req.body.attachments && req.body.attachments.map((a) => { return { filename: a.filename, path: a.path }; })) || []), ...downloadedMedia.map((a) => { return { path: a }; }) ] || null, html: isObject(req.body?.templateStrings) ? generateEmailTemplate(req.body.templateStrings) : req.body.html, ses: { // optional extra arguments for SendRawEmail Tags: [ { Name: "tag_name", Value: "tag_value" } ] } }, (err, info) => { if (info) { logger.log("send-email-success", "DEBUG", req?.user?.email, null, { from: `${req.body.from.name} <${req.body.from.address}>`, replyTo: req.body.ReplyTo.Email, to: req.body.to, cc: req.body.cc, subject: req.body.subject, templateStrings: req.body.templateStrings // info, }); logEmail(req, { to: req.body.to, cc: req.body.cc, subject: req.body.subject, messageId: info.response }); res.json({ success: true //response: info }); } else { logger.log("send-email-failure", "ERROR", req?.user?.email, null, { from: `${req.body.from.name} <${req.body.from.address}>`, replyTo: req.body.ReplyTo.Email, to: req.body.to, cc: req.body.cc, subject: req.body.subject, templateStrings: req.body.templateStrings, error: err }); logEmail(req, { to: req.body.to, cc: req.body.cc, subject: req.body.subject, bodyshopid: req.body.bodyshopid }); res.status(500).json({ success: false, error: err }); } } ); }; // This will be called by an SNS event trigger const emailBounce = async (req, res) => { try { const body = JSON.parse(req.body); if (body.Type === "SubscriptionConfirmation") { logger.log("SNS-message", "DEBUG", "api", null, { body: req.body }); } const message = JSON.parse(body.Message); if (message.notificationType === "Bounce") { let replyTo, subject, messageId; message.mail.headers.forEach((header) => { if (header.name === "Reply-To") { replyTo = header.value; } else if (header.name === "Subject") { subject = header.value; } }); messageId = message.mail.messageId; if ( replyTo === InstanceManager({ imex: "noreply@imex.online", rome: "noreply@romeonline.io" }) ) { res.sendStatus(200); return; } //If it's bounced, log it as bounced in audit log. Send an email to the user. const result = await client.request(queries.UPDATE_EMAIL_AUDIT, { sesid: messageId, status: "Bounced", context: message.bounce?.bouncedRecipients }); mailer.sendMail( { from: InstanceMgr({ imex: `ImEX Online `, rome: `Rome Online ` }), to: replyTo, //bcc: "patrick@snapt.ca", subject: `${InstanceMgr({ imex: "ImEX Online", rome: "Rome Online" })} Bounced Email - RE: ${subject}`, text: `${InstanceMgr({ imex: "ImEX Online", rome: "Rome Online" })} has tried to deliver an email with the subject: ${subject} to the intended recipients but encountered an error. ${body.bounce?.bouncedRecipients.map( (r) => `Recipient: ${r.emailAddress} | Status: ${r.action} | Code: ${r.diagnosticCode} ` )} ` }, (err, info) => { logger.log("sns-error", err ? "error" : "debug", "api", null, { message: err ? JSON.stringify(error) : info }); } ); } } catch (error) { logger.log("sns-error", "ERROR", "api", null, { error: JSON.stringify(error) }); } res.sendStatus(200); }; module.exports = { sendEmail, sendServerEmail, sendTaskEmail, emailBounce };