0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

🎨 Improved preview text on member alert emails (#15543)

refs/closes TryGhost/Team#2014
- Updated preview text.
- By default email client pulls text from email body for preview. Was added spaces to prevent such behaviour.
This commit is contained in:
Elena Baidakova 2022-10-07 14:31:05 +04:00 committed by GitHub
parent 38e06954a3
commit b3a33760ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 58 additions and 7 deletions

View file

@ -111,7 +111,12 @@
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 600px; padding: 30px 20px;">
<!-- START CENTERED CONTAINER -->
<span class="preheader" style="color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;"></span>
{{#> preview}}
{{#*inline "content"}}
Congratulations! You have a new free member.
{{/inline}}
{{/preview}}
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 8px;">
<!-- START MAIN CONTENT AREA -->

View file

@ -111,9 +111,16 @@
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 600px; padding: 30px 20px;">
<!-- START CENTERED CONTAINER -->
<span class="preheader" style="color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">
{{#if subscriptionData.cancellationReason}}Reason: {{subscriptionData.cancellationReason}} - {{/if}}
</span>
{{#> preview}}
{{#*inline "content"}}
{{#if subscriptionData.cancellationReason}}
Reason: {{subscriptionData.cancellationReason}}
{{else}}
A paid member has just canceled their subscription.
{{/if}}
{{/inline}}
{{/preview}}
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 8px;">
<!-- START MAIN CONTENT AREA -->

View file

@ -111,7 +111,12 @@
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 600px; padding: 30px 20px;">
<!-- START CENTERED CONTAINER -->
<span class="preheader" style="color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">{{tierData.name}} - {{tierData.details}} - </span>
{{#> preview}}
{{#*inline "content"}}
{{tierData.name}}: {{tierData.details}} {{#if offerData}}- Offer: {{offerData.name}} - {{offerData.details}}{{/if}}
{{/inline}}
{{/preview}}
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 8px;">
<!-- START MAIN CONTENT AREA -->

View file

@ -0,0 +1,6 @@
<span class="preheader" style="color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">
{{> content}}
<!-- Add spaces to prevent pulling text from email body to preview -->
&zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj;
&zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj; &zwnj;
</span>

View file

@ -1,6 +1,7 @@
const {promises: fs} = require('fs');
const {promises: fs, readFileSync} = require('fs');
const path = require('path');
const moment = require('moment');
const glob = require('glob');
class StaffServiceEmails {
constructor({logging, models, mailer, settingsHelpers, settingsCache, urlUtils}) {
@ -12,6 +13,7 @@ class StaffServiceEmails {
this.urlUtils = urlUtils;
this.Handlebars = require('handlebars');
this.registerPartials();
}
async notifyFreeMemberSignup(member, options) {
@ -271,6 +273,17 @@ class StaffServiceEmails {
return this.mailer.send(msg);
}
registerPartials() {
const rootDirname = './email-templates/partials/';
const files = glob.sync('*.hbs', {cwd: path.join(__dirname, rootDirname)});
files.forEach((fileName) => {
const name = fileName.replace(/.hbs$/, '');
const filePath = path.join(__dirname, rootDirname, `${name}.hbs`);
const content = readFileSync(filePath, 'utf8');
this.Handlebars.registerPartial(name, content);
});
}
async renderEmailTemplate(templateName, data) {
const htmlTemplateSource = await fs.readFile(path.join(__dirname, './email-templates/', `${templateName}.hbs`), 'utf8');
const htmlTemplate = this.Handlebars.compile(Buffer.from(htmlTemplateSource).toString());

View file

@ -417,6 +417,11 @@ describe('StaffService', function () {
mailStub.calledWith(
sinon.match.has('html', 'Offer')
).should.be.false();
// check preview text
mailStub.calledWith(
sinon.match.has('html', sinon.match('Test Tier: $50.00/month'))
).should.be.true();
});
it('sends paid subscription start alert with percent offer - first payment', async function () {
@ -434,6 +439,11 @@ describe('StaffService', function () {
mailStub.calledWith(
sinon.match.has('html', sinon.match('first payment'))
).should.be.true();
// check preview text
mailStub.calledWith(
sinon.match.has('html', sinon.match('Test Tier: $50.00/month - Offer: Half price - 50% off, first payment'))
).should.be.true();
});
it('sends paid subscription start alert with fixed type offer - repeating duration', async function () {
@ -561,7 +571,7 @@ describe('StaffService', function () {
).should.be.false();
mailStub.calledWith(
sinon.match.has('html', sinon.match('Reason: Changed my mind! - '))
sinon.match.has('html', sinon.match('Reason: Changed my mind!'))
).should.be.true();
mailStub.calledWith(
sinon.match.has('html', sinon.match('Cancellation reason'))
@ -592,6 +602,11 @@ describe('StaffService', function () {
mailStub.calledWith(
sinon.match.has('html', sinon.match('Cancellation reason'))
).should.be.false();
// check preview text
mailStub.calledWith(
sinon.match.has('html', sinon.match('A paid member has just canceled their subscription.'))
).should.be.true();
});
});
});