agmission/Development/server/helpers/mailer.js

287 lines
9.0 KiB
JavaScript

'use strict';
const nodemailer = require('nodemailer'),
Email = require('email-templates'),
hbs = require('handlebars'),
assert = require('assert'),
fs = require('fs-extra'),
cloneDeep = require('clone-deep'),
path = require('path'),
utils = require('./utils'),
env = require('./env'),
{ Errors, DEFAULT_LANG } = require('./constants');
const { AppInputError } = require('./app_error');
const TemplateType = Object.freeze({
PUG: 'pug', // default
HANDLEBARS: 'hbs',
});
const Templates = Object.freeze({
RESET_PASSWORD: 'reset-password',
PASSWORD_RESET: 'password-reset',
UPDATE_PAYMENT: 'update-payment',
UPDATE_BILL_ADDRESS: 'update-address',
CURRENT_SUBSCRIPTIONS: 'current-subscriptions',
SUB_RENEWAL_REMIND: 'sub-renewal-remind',
SUB_TRIAL_END_REMIND: 'sub-trial-end-remind',
});
const transporter = nodemailer.createTransport({
host: env.SMTP_HOST,
port: env.SMTP_PORT,
secure: env.SMTP_SECURE,
auth: {
user: env.SMTP_USR,
pass: env.SMTP_PWD
},
// debug: true,
// logger: true
});
function registerHbsPartials(partialsPath) {
// Ref handlebars with vars in templates: https://github.com/forwardemail/email-templates/issues/283
// hbs is your own instance of handlebars, with partials
// Register all available partials under the emails' partials folder
const partialDir = path.join(process.cwd() + partialsPath);
// const partialFiles =
fs.readdir(partialDir, (err, partialFiles) => {
if (!err && !utils.isEmptyArray(partialFiles)) {
for (let i = 0; i < partialFiles.length; i++) {
const pfile = partialFiles[i];
hbs.registerPartial(path.basename(pfile, '.hbs'), require(path.join(partialDir, pfile)));
}
// Override consolidate's handlebars instance
// email.config.views.options.engineSource.requires.handlebars = hbs;
}
});
}
registerHbsPartials('/emails/partials/');
hbs.registerHelper('$t', function (key, options) {
// Translation helper to translate message by key or with hash
return options.data.root.t({ phrase: key, locale: options.data.root.locale }, options.hash);
});
require('handlebars-helpers')(['comparison']);
const agmMailSig = ['Best,', 'AgMision Team'];
const debugging = false;
const defaultMailOps = {
transport: transporter,
preview: debugging,
send: true,
i18n: {
locales: ['en', 'es', 'pt']
}
};
function init(ops) {
if (ops) {
Object.assign({}, defaultMailOps, ops);
}
}
function _toLocale(locals) {
if (!utils.isEmptyObj(locals) && !utils.hasProperty(locals, 'locale')) {
const _locals = cloneDeep(locals);
_locals.locale = _locals.lang || DEFAULT_LANG;
delete _locals.lang;
return _locals;
}
return locals;
}
/**
* Send an email with given template and additional info
* @param {*} template the template name
* @param {*} locals additional metadata
* @returns
*/
async function sendMail(template, locals, to, from) {
const email = await createEmail({ from: from, to: to });
return email.send({
template: template,
// message: {
// to: to,
// },
locals: _toLocale(locals)
});
}
/**
* Send a text email from to with the mail options
* @param {*} contentOps { subject: <the mail subject>, text: <the text body content> }
*/
async function sendTextMail(contentOps, to, cc) {
if (utils.isEmptyObj(contentOps))
return;
const _mailOps = Object.assign(contentOps,
{
from: 'AgMission <noreply@agnav.com>',
to: to || 'agm_admin@agnav.com'
});
if (cc) _mailOps.cc = cc;
return transporter.sendMail(_mailOps);
}
/**
* Create an Email instance
* @param {*} emailOps { from, to }
*/
async function createEmail(emailOps, templateType = TemplateType.PUG) {
let _ops = Object.assign(
{
message: {
from: emailOps && emailOps.from || 'AgMission <noreply@agnav.com>'
}
},
defaultMailOps);
if (templateType === 'hbs') {
_ops = {
..._ops, views: {
options: {
extension: 'hbs'
},
engineSource: { requires: { handlebars: hbs } }
},
/* For relative assets or ones located within the same server */
// juice: true,
// juiceResources: {
// webResources: {
// images: true,
// // relativeTo: path.join(process.cwd(), '/emails/assets'),
// }
// }
}
}
if (emailOps && emailOps.to) {
_ops.message.to = emailOps.to;
}
const email = new Email(_ops);
return email;
}
async function sendHandlebarsEmail(template, locals, to, from = null) {
assert(template, AppInputError.create(Errors.TEMPLATE_NOT_FOUND));
assert(to, AppInputError.create(Errors.TO_NOT_FOUND));
const email = await createEmail({ locale: 'pt', to: to }, TemplateType.HANDLEBARS);
await email.send({
template: template,
locals: {
..._toLocale(locals)
}
});
}
/**
* Send update payment email notification so the customer can decide to update with a new payment method to continue using services
* @param {*} locals { locale: 'en', name, pmType: 'American Visa', pmEnding: '4321', hostname: 'localhost' }
* @param {*} to the destination email address.
* @param {*} from (Optional) the sender email address.
*/
async function sendUpdatePaymentEmail(locals, to, from) {
assert(locals && locals.name && locals.hostname, AppInputError.create());
locals.updatePmUrl = `https://${locals.hostname}/update-pm`;
await sendHandlebarsEmail(Templates.UPDATE_PAYMENT, locals, to, from);
}
/**
* Send update Billing Address email notification so the customer can decide to update with a valid address (for tax purpose).
* @param {*} locals { locale: 'en', userId, name, address: {line1, line2, city, state, postalCode, Country (country name)}, hostname: 'localhost' }
* @param {*} to the destination email address.
* @param {*} from (Optional) the sender email address.
*/
async function sendUpdateBillingAddressEmail(locals, to, from) {
assert(locals && locals.userId && locals.name && locals.hostname && !utils.isEmptyObj(locals.address), AppInputError.create());
locals.updateAddrUrl = `https://${locals.hostname}/update-bill-address/${locals.userId}`;
await sendHandlebarsEmail(Templates.UPDATE_BILL_ADDRESS, locals, to, from);
}
/**
* Send confirmation email with current subscriptions to the customer email address (normally after any subscription updates)
* @param {*} locals { locale: 'en', userId, name, package: [{ name, billCyle, startDate }], addon: [name, quantity, billCyle, startDate] }
* @param {*} to the destination email address.
* @param {*} from (Optional) the sender email address.
*/
async function sendCurSubcriptionsEmail(locals, to, from) {
assert(locals && locals.name, AppInputError.create());
await sendHandlebarsEmail(Templates.CURRENT_SUBSCRIPTIONS, locals, to, from);
}
/**
* Send upcoming renewal reminder of a subscription to the customer (auto-renewal enabled)
* @param {*} locals { subName, upPmDate, cardType, cardEnding, chargeAmount, hostname: 'localhost' }
* @param {*} to the destination email address.
* @param {*} from (Optional) the sender email address.
* */
async function sendSubRenewalRemindEmail(locals, to, from) {
assert(locals && locals.name && locals.hostname, AppInputError.create());
await sendHandlebarsEmail(Templates.SUB_RENEWAL_REMIND, locals, to, from);
}
/**
* Send trial ending reminder of a subscription to the customer (auto-renewal enabled)
* @param {*} locals { subName, upPmDate, cardType, cardEnding, chargeAmount, hostname: 'localhost' }
* @param {*} to the destination email address.
* @param {*} from (Optional) the sender email address.
* */
async function sendSubTrialEndingRemindEmail(locals, to, from) {
assert(locals && locals.name && locals.hostname, AppInputError.create());
locals.manageSubUrl = `https://${locals.hostname}/manage-subscription/${locals.userId}`;
await sendHandlebarsEmail(Templates.SUB_TRIAL_END_REMIND, locals, to, from);
}
// NOTE: For Testing only
async function sendTestMail(req, res) {
let sent = true;
try {
// const custId = '5a1d6c05ffb94e7875c68dd9';
// const updateUrl = `https://${req.hostname}/update-pm/${custId}`;
// await sendHandlebarsEmail(
// Templates.UPDATE_PAYMENT,
// { locale: 'en', name: 'Trung Hoang', pmType: 'American Visa', pmEnding: '4321', updatePmUrl: updateUrl },
// 'trungh@agnav.com',
// );
await sendHandlebarsEmail(
Templates.CURRENT_SUBSCRIPTIONS,
{
name: "Trung Hoang",
// package: [{ name: "ess_2", billCycle: "year", startDate: utils.timestampToDate(1692720405) }],
// addon: [{ name: "addon_1", billCycle: "month", quantity: 1, startDate: utils.timestampToDate(1692720405) }]
},
'trungh@agnav.com, trungduyhoang@gmail.com',
);
} catch (err) {
console.log(err);
sent = false;
}
res.send({ msg: `Message sent ${sent}` }).end();
}
module.exports = {
agmMailSig, sendMail, sendTextMail, sendUpdatePaymentEmail, sendUpdateBillingAddressEmail, sendCurSubcriptionsEmail, sendSubTrialEndingRemindEmail, sendSubRenewalRemindEmail,
sendTestMail
}