diff --git a/core/server/services/mega/post-email-serializer.js b/core/server/services/mega/post-email-serializer.js index bb4085f4b2..d9300382b4 100644 --- a/core/server/services/mega/post-email-serializer.js +++ b/core/server/services/mega/post-email-serializer.js @@ -15,6 +15,30 @@ const logging = require('@tryghost/logging'); const ALLOWED_REPLACEMENTS = ['first_name']; +// Format a full html document ready for email by inlining CSS, adjusting links, +// and performing any client-specific fixes +const formatHtmlForEmail = function formatHtmlForEmail(html) { + const juiceOptions = {inlinePseudoElements: true}; + + let juicedHtml = juice(html, juiceOptions); + + // convert juiced HTML to a DOM-like interface for further manipulation + // happens after inlining of CSS so we can change element types without worrying about styling + const _cheerio = cheerio.load(juicedHtml); + + // force all links to open in new tab + _cheerio('a').attr('target', '_blank'); + // convert figure and figcaption to div so that Outlook applies margins + _cheerio('figure, figcaption').each((i, elem) => !!(elem.tagName = 'div')); + + juicedHtml = _cheerio.html(); + + // Fix any unsupported chars in Outlook + juicedHtml = juicedHtml.replace(/'/g, '''); + + return juicedHtml; +}; + const getSite = () => { const publicSettings = settingsCache.getPublic(); return Object.assign({}, publicSettings, { @@ -273,25 +297,9 @@ const serialize = async (postModel, options = {isBrowserPreview: false, apiVersi htmlTemplate = htmlTemplate.replace('%recipient.unsubscribe_url%', previewUnsubscribeUrl); } - // Inline css to style attributes, turn on support for pseudo classes. - const juiceOptions = {inlinePseudoElements: true}; - let juicedHtml = juice(htmlTemplate, juiceOptions); - - // convert juiced HTML to a DOM-like interface for further manipulation - // happens after inlining of CSS so we can change element types without worrying about styling - _cheerio = cheerio.load(juicedHtml); - // force all links to open in new tab - _cheerio('a').attr('target','_blank'); - // convert figure and figcaption to div so that Outlook applies margins - _cheerio('figure, figcaption').each((i, elem) => !!(elem.tagName = 'div')); - juicedHtml = _cheerio.html(); - - // Fix any unsupported chars in Outlook - juicedHtml = juicedHtml.replace(/'/g, '''); - // Clean up any unknown replacements strings to get our final content const {html, plaintext} = normalizeReplacementStrings({ - html: juicedHtml, + html: formatHtmlForEmail(htmlTemplate), plaintext: post.plaintext }); @@ -314,7 +322,8 @@ function renderEmailForSegment(email, memberSegment) { $(node).removeAttr('data-gh-segment'); } }); - result.html = $.html(); + + result.html = formatHtmlForEmail($.html()); result.plaintext = htmlToPlaintext(result.html); return result;