mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-30 14:22:07 +03:00
bd597db829
- This is part of the quest to separate the frontend and server & get rid of all the places where there are cross-requires - At the moment the settings cache is one big shared cache used by the frontend and server liberally - This change doesn't really solve the fundamental problems, as we still depend on events, and requires from inside frontend - However it allows us to control the misuse slightly better by getting rid of restricted requires and turning on that eslint ruleset
123 lines
3.8 KiB
JavaScript
123 lines
3.8 KiB
JavaScript
const _ = require('lodash');
|
|
const {URL} = require('url');
|
|
const mailgun = require('mailgun-js');
|
|
const logging = require('@tryghost/logging');
|
|
const configService = require('../../../shared/config');
|
|
const settingsCache = require('../../../shared/settings-cache');
|
|
|
|
const BATCH_SIZE = 1000;
|
|
|
|
function createMailgun(config) {
|
|
const baseUrl = new URL(config.baseUrl);
|
|
|
|
return mailgun({
|
|
apiKey: config.apiKey,
|
|
domain: config.domain,
|
|
protocol: baseUrl.protocol,
|
|
host: baseUrl.hostname,
|
|
port: baseUrl.port,
|
|
endpoint: baseUrl.pathname,
|
|
retry: 5
|
|
});
|
|
}
|
|
|
|
function getInstance() {
|
|
const bulkEmailConfig = configService.get('bulkEmail');
|
|
const bulkEmailSetting = {
|
|
apiKey: settingsCache.get('mailgun_api_key'),
|
|
domain: settingsCache.get('mailgun_domain'),
|
|
baseUrl: settingsCache.get('mailgun_base_url')
|
|
};
|
|
const hasMailgunConfig = !!(bulkEmailConfig && bulkEmailConfig.mailgun);
|
|
const hasMailgunSetting = !!(bulkEmailSetting && bulkEmailSetting.apiKey && bulkEmailSetting.baseUrl && bulkEmailSetting.domain);
|
|
|
|
if (!hasMailgunConfig && !hasMailgunSetting) {
|
|
logging.warn(`Bulk email service is not configured`);
|
|
} else {
|
|
let mailgunConfig = hasMailgunConfig ? bulkEmailConfig.mailgun : bulkEmailSetting;
|
|
return createMailgun(mailgunConfig);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// recipientData format:
|
|
// {
|
|
// 'test@example.com': {
|
|
// name: 'Test User',
|
|
// unique_id: '12345abcde',
|
|
// unsubscribe_url: 'https://example.com/unsub/me'
|
|
// }
|
|
// }
|
|
function send(message, recipientData, replacements) {
|
|
if (recipientData.length > BATCH_SIZE) {
|
|
// err - too many recipients
|
|
}
|
|
|
|
let messageData = {};
|
|
|
|
try {
|
|
const bulkEmailConfig = configService.get('bulkEmail');
|
|
const mailgunInstance = getInstance();
|
|
|
|
const messageContent = _.pick(message, 'subject', 'html', 'plaintext');
|
|
|
|
// update content to use Mailgun variable syntax for replacements
|
|
replacements.forEach((replacement) => {
|
|
messageContent[replacement.format] = messageContent[replacement.format].replace(
|
|
replacement.match,
|
|
`%recipient.${replacement.id}%`
|
|
);
|
|
});
|
|
|
|
messageData = {
|
|
to: Object.keys(recipientData),
|
|
from: message.from,
|
|
'h:Reply-To': message.replyTo || message.reply_to,
|
|
subject: messageContent.subject,
|
|
html: messageContent.html,
|
|
text: messageContent.plaintext,
|
|
'recipient-variables': recipientData
|
|
};
|
|
|
|
// add a reference to the original email record for easier mapping of mailgun event -> email
|
|
if (message.id) {
|
|
messageData['v:email-id'] = message.id;
|
|
}
|
|
|
|
const tags = ['bulk-email'];
|
|
if (bulkEmailConfig && bulkEmailConfig.mailgun && bulkEmailConfig.mailgun.tag) {
|
|
tags.push(bulkEmailConfig.mailgun.tag);
|
|
}
|
|
messageData['o:tag'] = tags;
|
|
|
|
if (bulkEmailConfig && bulkEmailConfig.mailgun && bulkEmailConfig.mailgun.testmode) {
|
|
messageData['o:testmode'] = true;
|
|
}
|
|
|
|
// enable tracking if turned on for this email
|
|
if (message.track_opens) {
|
|
messageData['o:tracking-opens'] = true;
|
|
}
|
|
|
|
return new Promise((resolve, reject) => {
|
|
mailgunInstance.messages().send(messageData, (error, body) => {
|
|
if (error || !body) {
|
|
return reject(error);
|
|
}
|
|
|
|
return resolve({
|
|
id: body.id
|
|
});
|
|
});
|
|
});
|
|
} catch (error) {
|
|
return Promise.reject({error, messageData});
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
BATCH_SIZE,
|
|
getInstance,
|
|
send
|
|
};
|