Added support for eu Mailgun domain (#73)

closes: https://github.com/TryGhost/Ghost/issues/14640

- eu mailgun domains have a different structure. 
- we weren't accounting for this when fetching the next page of results, meaning that email stats didn't work on EU domains
This commit is contained in:
ceecko 2022-05-02 20:08:30 +02:00 committed by GitHub
parent 7d25bbec89
commit a9cce0281d
4 changed files with 197 additions and 2 deletions

View File

@ -109,8 +109,9 @@ class EmailAnalyticsProviderMailgun {
break pagesLoop; break pagesLoop;
} }
debug(`_fetchPages: starting fetching next page ${page.paging.next.replace('https://api.mailgun.net/v3', '')}`); const nextPageUrl = page.paging.next.replace(/https:\/\/api\.(eu\.)?mailgun\.net\/v3/, '');
page = await mailgun.get(page.paging.next.replace('https://api.mailgun.net/v3', '')); debug(`_fetchPages: starting fetching next page ${nextPageUrl}`);
page = await mailgun.get(nextPageUrl);
events = page && page.items && page.items.map(this.normalizeEvent) || []; events = page && page.items && page.items.map(this.normalizeEvent) || [];
debug(`_fetchPages: finished fetching next page with ${events.length} events`); debug(`_fetchPages: finished fetching next page with ${events.length} events`);
} }

View File

@ -0,0 +1,64 @@
{
"items": [
{
"event": "delivered",
"recipient": "recipient1@gmail.com",
"user-variables": {
"email-id": "5fbe5d9607bdfa3765dc3819"
},
"message": {
"headers": {
"message-id": "0201125133533.1.C55897076DBD42F2@domain.com"
}
},
"timestamp": 1606399301.266528
},
{
"event": "failed",
"severity": "temporary",
"recipient": "recipient2@gmail.com",
"user-variables": {
"email-id": "5fbe5d9607bdfa3765dc3819"
},
"message": {
"headers": {
"message-id": "0201125133533.1.C55897076DBD42F2@domain.com"
}
},
"timestamp": 1606399301.266528
},
{
"event": "failed",
"severity": "permanent",
"recipient": "recipient3@gmail.com",
"user-variables": {
"email-id": "5fbe5d9607bdfa3765dc3819"
},
"message": {
"headers": {
"message-id": "0201125133533.1.C55897076DBD42F2@domain.com"
}
},
"timestamp": 1606399301.266528
},
{
"event": "unsubscribed",
"recipient": "recipient4@gmail.com",
"user-variables": {
"email-id": "5fbe5d9607bdfa3765dc3819"
},
"message": {
"headers": {
"message-id": "0201125133533.1.C55897076DBD42F2@domain.com"
}
},
"timestamp": 1606399301.266528
}
],
"paging": {
"previous": "https://api.eu.mailgun.net/v3/domain.com/events/all-1-previous",
"first": "https://api.eu.mailgun.net/v3/domain.com/events/all-1-first",
"last": "https://api.eu.mailgun.net/v3/domain.com/events/all-1-last",
"next": "https://api.eu.mailgun.net/v3/domain.com/events/all-1-next"
}
}

View File

@ -0,0 +1,37 @@
{
"items": [
{
"event": "delivered",
"recipient": "recipient5@gmail.com",
"user-variables": {
"email-id": "5fbe5d9607bdfa3765dc3819"
},
"message": {
"headers": {
"message-id": "0201125133533.1.C55897076DBD42F2@domain.com"
}
},
"timestamp": 1606399301.266528
},
{
"event": "failed",
"severity": "temporary",
"recipient": "recipient6@gmail.com",
"user-variables": {
"email-id": "5fbe5d9607bdfa3765dc3819"
},
"message": {
"headers": {
"message-id": "0201125133533.1.C55897076DBD42F2@domain.com"
}
},
"timestamp": 1606399301.266528
}
],
"paging": {
"previous": "https://api.eu.mailgun.net/v3/domain.com/events/all-2-previous",
"first": "https://api.eu.mailgun.net/v3/domain.com/events/all-2-first",
"last": "https://api.eu.mailgun.net/v3/domain.com/events/all-2-last",
"next": "https://api.eu.mailgun.net/v3/domain.com/events/all-2-next"
}
}

View File

@ -158,6 +158,51 @@ describe('EmailAnalyticsProviderMailgun', function () {
batchHandler.callCount.should.eql(2); // one per page batchHandler.callCount.should.eql(2); // one per page
}); });
it('supports EU Mailgun domain', async function () {
const configStub = sinon.stub(config, 'get');
configStub.withArgs('bulkEmail').returns({
mailgun: {
apiKey: 'apiKey',
domain: 'domain.com',
baseUrl: 'https://api.eu.mailgun.net/v3'
}
});
const firstPageMock = nock('https://api.eu.mailgun.net')
.get('/v3/domain.com/events')
.query({
event: 'delivered OR opened OR failed OR unsubscribed OR complained',
limit: 300,
tags: 'bulk-email'
})
.replyWithFile(200, `${__dirname}/fixtures/all-1-eu.json`, {
'Content-Type': 'application/json'
});
const secondPageMock = nock('https://api.eu.mailgun.net')
.get('/v3/domain.com/events/all-1-next')
.replyWithFile(200, `${__dirname}/fixtures/all-2-eu.json`, {
'Content-Type': 'application/json'
});
// requests continue until an empty items set is returned
nock('https://api.eu.mailgun.net')
.get('/v3/domain.com/events/all-2-next')
.reply(200, {'Content-Type': 'application/json'}, {
items: []
});
const mailgunProvider = new EmailAnalyticsProviderMailgun({config, settings});
const batchHandler = sinon.spy();
await mailgunProvider.fetchAll(batchHandler);
firstPageMock.isDone().should.be.true();
secondPageMock.isDone().should.be.true();
batchHandler.callCount.should.eql(2); // one per page
});
it('uses custom tags when supplied', async function () { it('uses custom tags when supplied', async function () {
const configStub = sinon.stub(config, 'get'); const configStub = sinon.stub(config, 'get');
configStub.withArgs('bulkEmail').returns({ configStub.withArgs('bulkEmail').returns({
@ -253,6 +298,54 @@ describe('EmailAnalyticsProviderMailgun', function () {
batchHandler.callCount.should.eql(2); // one per page batchHandler.callCount.should.eql(2); // one per page
}); });
it('supports EU Mailgun domain', async function () {
const configStub = sinon.stub(config, 'get');
configStub.withArgs('bulkEmail').returns({
mailgun: {
apiKey: 'apiKey',
domain: 'domain.com',
baseUrl: 'https://api.eu.mailgun.net/v3'
}
});
const firstPageMock = nock('https://api.eu.mailgun.net')
.get('/v3/domain.com/events')
.query({
event: 'delivered OR opened OR failed OR unsubscribed OR complained',
limit: 300,
tags: 'bulk-email',
begin: 'Thu, 25 Feb 2021 11:30:00 GMT', // latest minus threshold
ascending: 'yes'
})
.replyWithFile(200, `${__dirname}/fixtures/all-1-eu.json`, {
'Content-Type': 'application/json'
});
const secondPageMock = nock('https://api.eu.mailgun.net')
.get('/v3/domain.com/events/all-1-next')
.replyWithFile(200, `${__dirname}/fixtures/all-2-eu.json`, {
'Content-Type': 'application/json'
});
// requests continue until an empty items set is returned
nock('https://api.eu.mailgun.net')
.get('/v3/domain.com/events/all-2-next')
.reply(200, {'Content-Type': 'application/json'}, {
items: []
});
const mailgunProvider = new EmailAnalyticsProviderMailgun({config, settings});
const batchHandler = sinon.spy();
const latestTimestamp = new Date('Thu Feb 25 2021 12:00:00 GMT+0000');
await mailgunProvider.fetchLatest(latestTimestamp, batchHandler);
firstPageMock.isDone().should.be.true();
secondPageMock.isDone().should.be.true();
batchHandler.callCount.should.eql(2); // one per page
});
it('uses custom tags when supplied', async function () { it('uses custom tags when supplied', async function () {
const configStub = sinon.stub(config, 'get'); const configStub = sinon.stub(config, 'get');
configStub.withArgs('bulkEmail').returns({ configStub.withArgs('bulkEmail').returns({