diff --git a/ghost/core/core/server/services/email-service/wrapper.js b/ghost/core/core/server/services/email-service/wrapper.js index d664c02dc5..150f9c3eed 100644 --- a/ghost/core/core/server/services/email-service/wrapper.js +++ b/ghost/core/core/server/services/email-service/wrapper.js @@ -14,7 +14,7 @@ class EmailServiceWrapper { } const {EmailService, EmailController, EmailRenderer, SendingService, BatchSendingService, EmailSegmenter, EmailEventStorage, MailgunEmailProvider} = require('@tryghost/email-service'); - const {Post, Newsletter, Email, EmailBatch, EmailRecipient, Member, EmailRecipientFailure} = require('../../models'); + const {Post, Newsletter, Email, EmailBatch, EmailRecipient, Member, EmailRecipientFailure, EmailSpamComplaintEvent} = require('../../models'); const MailgunClient = require('@tryghost/mailgun-client'); const configService = require('../../../shared/config'); const settingsCache = require('../../../shared/settings-cache'); @@ -114,7 +114,8 @@ class EmailServiceWrapper { db, membersRepository, models: { - EmailRecipientFailure + EmailRecipientFailure, + EmailSpamComplaintEvent } }); this.eventStorage.listen(domainEvents); diff --git a/ghost/core/test/integration/services/email-service/email-event-storage.test.js b/ghost/core/test/integration/services/email-service/email-event-storage.test.js index 3ca170d24e..5a702eeea1 100644 --- a/ghost/core/test/integration/services/email-service/email-event-storage.test.js +++ b/ghost/core/test/integration/services/email-service/email-event-storage.test.js @@ -767,10 +767,13 @@ describe('EmailEventStorage', function () { const memberId = emailRecipient.member_id; const providerId = emailBatch.provider_id; const timestamp = new Date(2000, 0, 1); + const eventsURI = '/members/events/?' + encodeURIComponent( + `filter=type:-[comment_event,aggregated_click_event]+data.member_id:${memberId}` + ); // Check not unsubscribed - const memberInitial = await membersService.api.members.get({id: memberId}, {withRelated: ['newsletters']}); - assert.notEqual(memberInitial.related('newsletters').length, 0, 'This test requires a member that is subscribed to at least one newsletter'); + const {body: {events: [notSpamEvent]}} = await agent.get(eventsURI); + assert.notEqual(notSpamEvent.type, 'email_complaint_event', 'This test requires a member that does not have a spam event'); events = [{ event: 'complained', @@ -799,9 +802,9 @@ describe('EmailEventStorage', function () { // Now wait for events processed await sleep(200); - // Check if unsubscribed - const member = await membersService.api.members.get({id: memberId}, {withRelated: ['newsletters']}); - assert.equal(member.related('newsletters').length, 0); + // Check if event exists + const {body: {events: [spamComplaintEvent]}} = await agent.get(eventsURI); + assert.equal(spamComplaintEvent.type, 'email_complaint_event'); }); it('Can handle unsubscribe events', async function () { diff --git a/ghost/email-service/lib/email-event-storage.js b/ghost/email-service/lib/email-event-storage.js index b73c20ff93..da4d27d005 100644 --- a/ghost/email-service/lib/email-event-storage.js +++ b/ghost/email-service/lib/email-event-storage.js @@ -13,6 +13,9 @@ class EmailEventStorage { this.#membersRepository = membersRepository; } + /** + * @param {import('@tryghost/domain-events')} domainEvents + */ listen(domainEvents) { domainEvents.subscribe(EmailDeliveredEvent, async (event) => { try { @@ -100,9 +103,9 @@ class EmailEventStorage { /** * @private * @param {'temporary'|'permanent'} severity - * @param {import('@tryghost/email-events').EmailTemporaryBouncedEvent|import('@tryghost/email-events').EmailBouncedEvent} event - * @param {{transacting?: any}} options - * @returns + * @param {import('@tryghost/email-events').EmailTemporaryBouncedEvent|import('@tryghost/email-events').EmailBouncedEvent} event + * @param {{transacting?: any}} options + * @returns */ async saveFailure(severity, event, options = {}) { if (!event.error) { @@ -144,7 +147,7 @@ class EmailEventStorage { /// We can get events out of order, so only save the last one return; } - + // Update the existing failure await existing.save({ severity, @@ -162,7 +165,11 @@ class EmailEventStorage { } async handleComplained(event) { - return this.unsubscribeFromNewsletters(event); + await this.#models.EmailSpamComplaintEvent.add({ + member_id: event.memberId, + email_id: event.emailId, + email_address: event.email + }); } async unsubscribeFromNewsletters(event) {