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, errorMessage: error?.message, errorStack: error?.stack // 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: ["support@thinkimex.com"], subject: subject, text: text, ses: { // optional extra arguments for SendRawEmail Tags: [ { Name: "tag_name", Value: "tag_value" } ] } }, // eslint-disable-next-line no-unused-vars (err, info) => { logger.log("server-email-failure", err ? "error" : "debug", null, null, { message: err?.message, stack: err?.stack }); } ); } catch (error) { logger.log("server-email-failure", "error", null, null, { message: error?.message, stack: error?.stack }); } }; const sendWelcomeEmail = async ({ to, resetLink, dateLine, features, bcc }) => { try { await mailer.sendMail({ from: InstanceManager({ imex: `ImEX Online `, rome: `Rome Online ` }), to, bcc, subject: InstanceManager({ imex: "Welcome to the ImEX Online platform.", rome: "Welcome to the Rome Online platform." }), html: generateEmailTemplate({ header: InstanceManager({ imex: "Welcome to the ImEX Online platform.", rome: "Welcome to the Rome Online platform." }), subHeader: `Your ${InstanceManager({imex: features?.allAccess ? "ImEX Online": "ImEX Lite", rome: features?.allAccess ? "RO Manager" : "RO Basic"})} shop setup has been completed, and this email will include all the information you need to begin.`, body: `

To finish setting up your account, visit this link and enter your desired password. Reset Password

To access your ${InstanceManager({imex: features.allAccess ? "ImEX Online": "ImEX Lite", rome: features.allAccess ? "RO Manager" : "RO Basic"})} shop, visit ${InstanceManager({imex: "imex.online", rome: "romeonline.io"})}. Your username is your email, and your password is what you previously set up. Contact support for additional logins.

${InstanceManager({ rome: `

To push estimates over from your estimating system, you must download the Web-Est EMS Unzipper & Rome Online Partner (Computers using Windows only). Here are some steps to help you get started.

Once you successfully set up the partner, now it's time to do some initial in-product items: Please note, an estimate must be exported from the estimating platform to use tours.

If you need any assistance with setting up the programs, or if you want a dedicated Q&A session with one of our customer success specialists, schedule by clicking this link - Rome Basic Training Booking

If you have additional questions or need any support, feel free to use the RO Basic support chat (blue chat box located in the bottom right corner) or give us a call at (410) 357-6700. We are here to help make your experience seamless!

` })}

In addition to the training tour, you can also book a live one-on-one demo to see exactly how our system can help streamline the repair process at your shop, schedule by clicking this link - ${InstanceManager({imex: "ImEX Lite", rome: "Rome Basic"})} Demo Booking

Thanks,

The ${InstanceManager({imex: "ImEX Online", rome: "Rome Online"})} Team

`, dateLine }) }); } 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 }, // eslint-disable-next-line no-unused-vars (err, info) => { // (message, type, user, record, meta logger.log("server-email", err ? "error" : "debug", null, null, { message: err?.message, stack: err?.stack }); } ); } catch (error) { logger.log("server-email-failure", "error", null, null, { message: error?.message, stack: error?.stack }); } }; // 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, errorMessage: error?.message, errorStack: error?.stack }); } }) ); } 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 }; }) ], 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, errorMessage: err?.message, errorStack: err?.stack }); logEmail(req, { to: req.body.to, cc: req.body.cc, subject: req.body.subject, bodyshopid: req.body.bodyshopid }); res.status(500).json({ success: false, errorMessage: err?.message, stack: err?.stack }); } } ); }; // 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. await client.request(queries.UPDATE_EMAIL_AUDIT, { sesid: messageId, status: "Bounced", context: message.bounce?.bouncedRecipients }); mailer.sendMail( { from: InstanceManager({ imex: `ImEX Online `, rome: `Rome Online ` }), to: replyTo, //bcc: "patrick@snapt.ca", subject: `${InstanceManager({ imex: "ImEX Online", rome: "Rome Online" })} Bounced Email - RE: ${subject}`, text: `${InstanceManager({ 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} ` )} ` }, // eslint-disable-next-line no-unused-vars (err, info) => { logger.log("sns-error", err ? "error" : "debug", "api", null, { errorMessage: err?.message, errorStack: err?.stack }); } ); } } catch (error) { logger.log("sns-error", "ERROR", "api", null, { errorMessage: error?.message, errorStack: error?.stack }); } res.sendStatus(200); }; module.exports = { sendEmail, sendServerEmail, sendTaskEmail, emailBounce, sendWelcomeEmail };