From 14f282d640f60ab9ccf6b6d7c6a7cf88b7668a77 Mon Sep 17 00:00:00 2001 From: Fabien 'egg' O'Carroll Date: Fri, 13 Jan 2023 15:46:57 +0700 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Improved=20newsletter=20delivery=20?= =?UTF-8?q?rates=20and=20email=20suppression=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This introduces the new suppressions feature which will automatically unsubscribe members from newsletters when their email is added to the suppression list in Mailgun, this is usually due to emails either permanently bouncing to the address, or the member making a spam complaint. Both Members and Admins are able to see that the email has been added to the list, and Members are be able to request their email be removed from the list via Portal. Overall this feature should improve delivery rates of newsletters and improve the rating of the domain you're sending from. --- ...-13-04-25-unsubscribe-suppressed-emails.js | 21 +++++++++++++++++++ ghost/core/core/shared/labs.js | 2 +- .../admin/__snapshots__/settings.test.js.snap | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 ghost/core/core/server/data/migrations/versions/5.30/2023-01-13-04-25-unsubscribe-suppressed-emails.js diff --git a/ghost/core/core/server/data/migrations/versions/5.30/2023-01-13-04-25-unsubscribe-suppressed-emails.js b/ghost/core/core/server/data/migrations/versions/5.30/2023-01-13-04-25-unsubscribe-suppressed-emails.js new file mode 100644 index 0000000000..ad63402e39 --- /dev/null +++ b/ghost/core/core/server/data/migrations/versions/5.30/2023-01-13-04-25-unsubscribe-suppressed-emails.js @@ -0,0 +1,21 @@ +const logging = require('@tryghost/logging'); + +const {createTransactionalMigration} = require('../../utils'); + +module.exports = createTransactionalMigration( + async function up(knex) { + const membersWithSuppressedEmails = await knex.select('members.id').from('members').innerJoin('suppressions', 'members.email', 'suppressions.email'); + + if (membersWithSuppressedEmails.length === 0) { + logging.info('No emails suppressions found'); + return; + } else { + logging.info(`Unsubscribing ${membersWithSuppressedEmails.length} members from newsletters due to email suppressions`); + } + + await knex('members_newsletters').whereIn('member_id', membersWithSuppressedEmails.map(member => member.id)).del(); + }, + async function down() { + logging.info('Not repopulating members_newsletters'); + } +); diff --git a/ghost/core/core/shared/labs.js b/ghost/core/core/shared/labs.js index 6ded57b8ef..1983530f1b 100644 --- a/ghost/core/core/shared/labs.js +++ b/ghost/core/core/shared/labs.js @@ -15,6 +15,7 @@ const messages = { // flags in this list always return `true`, allows quick global enable prior to full flag removal const GA_FEATURES = [ + 'suppressionList', 'sourceAttribution', 'memberAttribution', 'audienceFeedback', @@ -31,7 +32,6 @@ const ALPHA_FEATURES = [ 'urlCache', 'beforeAfterCard', 'lexicalEditor', - 'suppressionList', 'emailStability' ]; diff --git a/ghost/core/test/e2e-api/admin/__snapshots__/settings.test.js.snap b/ghost/core/test/e2e-api/admin/__snapshots__/settings.test.js.snap index 58b687397e..2851e407a4 100644 --- a/ghost/core/test/e2e-api/admin/__snapshots__/settings.test.js.snap +++ b/ghost/core/test/e2e-api/admin/__snapshots__/settings.test.js.snap @@ -635,7 +635,7 @@ exports[`Settings API Edit Can edit a setting 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "3497", + "content-length": "3522", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Accept-Version, Origin, Accept-Encoding",