UNPKG

strapi-plugin-email-designer

Version:
172 lines (142 loc) 6.25 kB
'use strict'; const _ = require('lodash'); const Mustache = require('mustache'); // From: https://stackoverflow.com/questions/201323/how-can-i-validate-an-email-address-using-a-regular-expression const isValidEmail = /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/; const decode = require('decode-html'); const { htmlToText } = require('html-to-text'); const { isEmpty } = require('lodash'); module.exports = ({ strapi }) => { const isMantainLegacyTemplateActive = () => _.get(strapi.plugins, 'email-designer.config.mantainLegacyTemplate', true); /** * fill subject, text and html using lodash template * @param {object} emailOptions - to, from and replyto... * @param {object} emailTemplate - object containing attributes to fill * @param {object} data - data used to fill the template * @returns Promise<{ subject, text, subject }> */ const sendTemplatedEmail = async (emailOptions = {}, emailTemplate = {}, data = {}) => { const keysToIgnore = ['attachment', 'attachments', 'headers']; Object.entries(emailOptions).forEach(([key, address]) => { if (!keysToIgnore.includes(key)) { if (Array.isArray(address)) { address.forEach((email) => { if (!isValidEmail.test(email)) throw new Error(`Invalid "${key}" email address with value "${email}"`); }); } else { if (!isValidEmail.test(address)) throw new Error(`Invalid "${key}" email address with value "${address}"`); } } }); const requiredAttributes = ['templateReferenceId']; const attributes = ['text', 'html', 'subject']; const missingAttributes = _.difference(requiredAttributes, Object.keys(emailTemplate)); if (missingAttributes.length > 0) { throw new Error(`Following attributes are missing from your email template : ${missingAttributes.join(', ')}`); } let bodyHtml, bodyText, subject; const { templateReferenceId } = emailTemplate || {}; const response = await strapi.db .query('plugin::email-designer.email-template') .findOne({ where: { templateReferenceId } }); if (!response) { strapi.log.error(`No email template found with referenceId "${templateReferenceId}"`); return null; } ({ bodyHtml, bodyText, subject } = response); if (isMantainLegacyTemplateActive()) { bodyHtml = bodyHtml.replace(/<%/g, '{{').replace(/%>/g, '}}'); bodyText = bodyText.replace(/<%/g, '{{').replace(/%>/g, '}}'); subject = subject.replace(/<%/g, '{{').replace(/%>/g, '}}'); } if ((!bodyText || !bodyText.length) && bodyHtml && bodyHtml.length) bodyText = htmlToText(bodyHtml, { wordwrap: 130, trimEmptyLines: true, uppercaseHeadings: false }); emailTemplate = { ...emailTemplate, subject: (!isEmpty(emailTemplate.subject) && emailTemplate.subject) || (!isEmpty(subject) && decode(subject)) || 'No Subject', html: decode(bodyHtml), text: decode(bodyText), }; const templatedAttributes = attributes.reduce( (compiled, attribute) => emailTemplate[attribute] ? Object.assign(compiled, { [attribute]: Mustache.render(emailTemplate[attribute], data) }) : compiled, {}, ); return strapi.plugin('email').provider.send({ ...emailOptions, ...templatedAttributes }); }; /** * @Deprecated * Promise to retrieve a composed HTML email. * @return {Promise} */ const compose = async ({ templateReferenceId, data = {} }) => { strapi.log.debug(`⚠️: `, `The 'compose' function is deprecated and may be removed or changed in the future.`); if (!templateReferenceId) throw new Error("No email template's id provided"); let { bodyHtml, bodyText, subject } = await strapi .query('plugin::email-designer.email-template') .findOne({ where: { templateReferenceId } }); if (isMantainLegacyTemplateActive()) { bodyHtml = bodyHtml.replace(/<%/g, '{{').replace(/%>/g, '}}'); bodyText = bodyText.replace(/<%/g, '{{').replace(/%>/g, '}}'); subject = subject.replace(/<%/g, '{{').replace(/%>/g, '}}'); } if ((!bodyText || !bodyText.length) && bodyHtml && bodyHtml.length) bodyText = htmlToText(bodyHtml, { wordwrap: 130, trimEmptyLines: true, uppercaseHeadings: false }); const emailTemplate = { html: decode(bodyHtml), text: decode(bodyText), }; const attributes = ['text', 'html']; const templatedAttributes = attributes.reduce( (compiled, attribute) => emailTemplate[attribute] ? Object.assign(compiled, { [attribute]: Mustache.render(emailTemplate[attribute], data) }) : compiled, {}, ); return { composedHtml: templatedAttributes.html, composedText: templatedAttributes.text, }; }; /** * @Deprecated * Promise to send a composed HTML email. * @return {Promise} */ const send = async ({ templateId, data, to, from, replyTo, subject }) => { strapi.log.debug(`⚠️: `, `The 'send' function is deprecated and may be removed or changed in the future.`); Object.entries({ to, from, replyTo }).forEach(([key, address]) => { if (!isValidEmail.test(address)) throw new Error(`Invalid "${key}" email address with value "${address}"`); }); try { const { composedHtml = '', composedText = '' } = await strapi.plugins['email-designer'].services.email.compose({ templateId, data, }); await strapi.plugins['email'].services.email.send({ to, from, replyTo, subject, html: composedHtml, text: composedText, }); } catch (err) { strapi.log.debug('📺: ', err); throw new Error(err); } }; return { sendTemplatedEmail, compose, send, }; };