Collect common mail sending configs in one function

This commit is contained in:
Johannes Zellner
2018-01-19 17:44:12 +01:00
parent 77206a9d3c
commit 18a781b956

View File

@@ -31,6 +31,7 @@ var assert = require('assert'),
config = require('./config.js'),
debug = require('debug')('box:mailer'),
docker = require('./docker.js').connection,
domains = require('./domains.js'),
ejs = require('ejs'),
nodemailer = require('nodemailer'),
path = require('path'),
@@ -59,12 +60,36 @@ function splatchError(error) {
return util.inspect(result, { depth: null, showHidden: true });
}
function mailConfig() {
return {
from: '"Cloudron" <no-reply@' + config.fqdn() + '>'
};
// This will collect the most common details required for notification emails
function getMailConfig(callback) {
assert.strictEqual(typeof callback, 'function');
getAdminEmails(function (error, adminEmails) {
if (error) return callback(error);
settings.getCloudronName(function (error, cloudronName) {
// this is not fatal
if (error) {
debug(error);
cloudronName = 'Cloudron';
}
domains.getAll(function (error, domains) {
if (error) return callback(error);
if (domains.length === 0) return callback('No domains configured');
callback(null, {
adminEmails: adminEmails,
cloudronName: cloudronName,
notificationDomain: domains[0].domain,
notificationFrom: '"' + cloudronName + '" <no-reply@' + domains[0].domain + '>'
});
});
});
});
}
function processQueue() {
sendMails(gMailQueue);
gMailQueue = [ ];
@@ -148,26 +173,19 @@ function mailUserEventToAdmins(user, event) {
assert.strictEqual(typeof user, 'object');
assert.strictEqual(typeof event, 'string');
settings.getCloudronName(function (error, cloudronName) {
if (error) {
debug(error);
cloudronName = 'Cloudron';
}
getMailConfig(function (error, mailConfig) {
if (error) return debug('Error getting mail details:', error);
getAdminEmails(function (error, adminEmails) {
if (error) return debug('Error getting admins', error);
var adminEmails = _.difference(mailConfig.adminEmails, [ user.email ]);
adminEmails = _.difference(adminEmails, [ user.email ]);
var mailOptions = {
from: mailConfig.notificationFrom,
to: adminEmails.join(', '),
subject: util.format('[%s] %s %s', mailConfig.cloudronName, user.username || user.alternateEmail || user.email, event),
text: render('user_event.ejs', { user: user, event: event, format: 'text' }),
};
var mailOptions = {
from: mailConfig().from,
to: adminEmails.join(', '),
subject: util.format('[%s] %s %s', cloudronName, user.username || user.alternateEmail || user.email, event),
text: render('user_event.ejs', { user: user, event: event, format: 'text' }),
};
enqueue(mailOptions);
});
enqueue(mailOptions);
});
}
@@ -177,18 +195,15 @@ function sendInvite(user, invitor) {
debug('Sending invite mail');
settings.getCloudronName(function (error, cloudronName) {
if (error) {
debug(error);
cloudronName = 'Cloudron';
}
getMailConfig(function (error, mailConfig) {
if (error) return debug('Error getting mail details:', error);
var templateData = {
user: user,
webadminUrl: config.adminOrigin(),
setupLink: config.adminOrigin() + '/api/v1/session/account/setup.html?reset_token=' + user.resetToken,
invitor: invitor,
cloudronName: cloudronName,
cloudronName: mailConfig.cloudronName,
cloudronAvatarUrl: config.adminOrigin() + '/api/v1/cloudron/avatar'
};
@@ -199,9 +214,9 @@ function sendInvite(user, invitor) {
templateDataHTML.format = 'html';
var mailOptions = {
from: mailConfig().from,
from: mailConfig.notificationFrom,
to: user.alternateEmail || user.email,
subject: util.format('Welcome to %s', cloudronName),
subject: util.format('Welcome to %s', mailConfig.cloudronName),
text: render('welcome_user.ejs', templateDataText),
html: render('welcome_user.ejs', templateDataHTML)
};
@@ -216,40 +231,33 @@ function userAdded(user, inviteSent) {
debug('Sending mail for userAdded %s including invite link', inviteSent ? 'not' : '');
getAdminEmails(function (error, adminEmails) {
if (error) return debug('Error getting admins', error);
getMailConfig(function (error, mailConfig) {
if (error) return debug('Error getting mail details:', error);
adminEmails = _.difference(adminEmails, [ user.email ]);
var adminEmails = _.difference(mailConfig.adminEmails, [ user.email ]);
settings.getCloudronName(function (error, cloudronName) {
if (error) {
debug(error);
cloudronName = 'Cloudron';
}
var templateData = {
user: user,
inviteLink: inviteSent ? null : config.adminOrigin() + '/api/v1/session/account/setup.html?reset_token=' + user.resetToken,
cloudronName: mailConfig.cloudronName,
cloudronAvatarUrl: config.adminOrigin() + '/api/v1/cloudron/avatar'
};
var templateData = {
user: user,
inviteLink: inviteSent ? null : config.adminOrigin() + '/api/v1/session/account/setup.html?reset_token=' + user.resetToken,
cloudronName: cloudronName,
cloudronAvatarUrl: config.adminOrigin() + '/api/v1/cloudron/avatar'
};
var templateDataText = JSON.parse(JSON.stringify(templateData));
templateDataText.format = 'text';
var templateDataText = JSON.parse(JSON.stringify(templateData));
templateDataText.format = 'text';
var templateDataHTML = JSON.parse(JSON.stringify(templateData));
templateDataHTML.format = 'html';
var templateDataHTML = JSON.parse(JSON.stringify(templateData));
templateDataHTML.format = 'html';
var mailOptions = {
from: mailConfig.notificationFrom,
to: adminEmails.join(', '),
subject: util.format('[%s] User %s added', mailConfig.cloudronName, user.alternateEmail || user.email),
text: render('user_added.ejs', templateDataText),
html: render('user_added.ejs', templateDataHTML)
};
var mailOptions = {
from: mailConfig().from,
to: adminEmails.join(', '),
subject: util.format('[%s] User %s added', cloudronName, user.alternateEmail || user.email),
text: render('user_added.ejs', templateDataText),
html: render('user_added.ejs', templateDataHTML)
};
enqueue(mailOptions);
});
enqueue(mailOptions);
});
}
@@ -275,16 +283,13 @@ function passwordReset(user) {
debug('Sending mail for password reset for user %s.', user.email, user.id);
settings.getCloudronName(function (error, cloudronName) {
if (error) {
debug(error);
cloudronName = 'Cloudron';
}
getMailConfig(function (error, mailConfig) {
if (error) return debug('Error getting mail details:', error);
var templateData = {
user: user,
resetLink: config.adminOrigin() + '/api/v1/session/password/reset.html?reset_token=' + user.resetToken,
cloudronName: cloudronName,
cloudronName: mailConfig.cloudronName,
cloudronAvatarUrl: config.adminOrigin() + '/api/v1/cloudron/avatar'
};
@@ -295,9 +300,9 @@ function passwordReset(user) {
templateDataHTML.format = 'html';
var mailOptions = {
from: mailConfig().from,
from: mailConfig.notificationFrom,
to: user.alternateEmail || user.email,
subject: util.format('[%s] Password Reset', cloudronName),
subject: util.format('[%s] Password Reset', mailConfig.cloudronName),
text: render('password_reset.ejs', templateDataText),
html: render('password_reset.ejs', templateDataHTML)
};
@@ -311,24 +316,17 @@ function appDied(app) {
debug('Sending mail for app %s @ %s died', app.id, app.fqdn);
getAdminEmails(function (error, adminEmails) {
if (error) return debug('Error getting admins', error);
getMailConfig(function (error, mailConfig) {
if (error) return debug('Error getting mail details:', error);
settings.getCloudronName(function (error, cloudronName) {
if (error) {
debug(error);
cloudronName = 'Cloudron';
}
var mailOptions = {
from: mailConfig.notificationFrom,
to: config.provider() === 'caas' ? 'support@cloudron.io' : mailConfig.adminEmails.join(', '),
subject: util.format('[%s] App %s is down', mailConfig.cloudronName, app.fqdn),
text: render('app_down.ejs', { title: app.manifest.title, appFqdn: app.fqdn, format: 'text' })
};
var mailOptions = {
from: mailConfig().from,
to: config.provider() === 'caas' ? 'support@cloudron.io' : adminEmails.join(', '),
subject: util.format('[%s] App %s is down', cloudronName, app.fqdn),
text: render('app_down.ejs', { title: app.manifest.title, appFqdn: app.fqdn, format: 'text' })
};
enqueue(mailOptions);
});
enqueue(mailOptions);
});
}
@@ -337,43 +335,36 @@ function boxUpdateAvailable(hasSubscription, newBoxVersion, changelog) {
assert.strictEqual(typeof newBoxVersion, 'string');
assert(util.isArray(changelog));
getAdminEmails(function (error, adminEmails) {
if (error) return debug('Error getting admins', error);
getMailConfig(function (error, mailConfig) {
if (error) return debug('Error getting mail details:', error);
settings.getCloudronName(function (error, cloudronName) {
if (error) {
debug(error);
cloudronName = 'Cloudron';
}
var converter = new showdown.Converter();
var converter = new showdown.Converter();
var templateData = {
webadminUrl: config.adminOrigin(),
newBoxVersion: newBoxVersion,
hasSubscription: hasSubscription,
changelog: changelog,
changelogHTML: changelog.map(function (e) { return converter.makeHtml(e); }),
cloudronName: mailConfig.cloudronName,
cloudronAvatarUrl: config.adminOrigin() + '/api/v1/cloudron/avatar'
};
var templateData = {
webadminUrl: config.adminOrigin(),
newBoxVersion: newBoxVersion,
hasSubscription: hasSubscription,
changelog: changelog,
changelogHTML: changelog.map(function (e) { return converter.makeHtml(e); }),
cloudronName: cloudronName,
cloudronAvatarUrl: config.adminOrigin() + '/api/v1/cloudron/avatar'
};
var templateDataText = JSON.parse(JSON.stringify(templateData));
templateDataText.format = 'text';
var templateDataText = JSON.parse(JSON.stringify(templateData));
templateDataText.format = 'text';
var templateDataHTML = JSON.parse(JSON.stringify(templateData));
templateDataHTML.format = 'html';
var templateDataHTML = JSON.parse(JSON.stringify(templateData));
templateDataHTML.format = 'html';
var mailOptions = {
from: mailConfig.notificationFrom,
to: mailConfig.adminEmails.join(', '),
subject: util.format('%s has a new update available', mailConfig.cloudronName),
text: render('box_update_available.ejs', templateDataText),
html: render('box_update_available.ejs', templateDataHTML)
};
var mailOptions = {
from: mailConfig().from,
to: adminEmails.join(', '),
subject: util.format('%s has a new update available', cloudronName),
text: render('box_update_available.ejs', templateDataText),
html: render('box_update_available.ejs', templateDataHTML)
};
enqueue(mailOptions);
});
enqueue(mailOptions);
});
}
@@ -382,129 +373,101 @@ function appUpdateAvailable(app, hasSubscription, info) {
assert.strictEqual(typeof hasSubscription, 'boolean');
assert.strictEqual(typeof info, 'object');
getAdminEmails(function (error, adminEmails) {
if (error) return debug('Error getting admins', error);
getMailConfig(function (error, mailConfig) {
if (error) return debug('Error getting mail details:', error);
settings.getCloudronName(function (error, cloudronName) {
if (error) {
debug(error);
cloudronName = 'Cloudron';
}
var converter = new showdown.Converter();
var converter = new showdown.Converter();
var templateData = {
webadminUrl: config.adminOrigin(),
hasSubscription: hasSubscription,
app: app,
updateInfo: info,
changelogHTML: converter.makeHtml(info.manifest.changelog),
cloudronName: mailConfig.cloudronName,
cloudronAvatarUrl: config.adminOrigin() + '/api/v1/cloudron/avatar'
};
var templateData = {
webadminUrl: config.adminOrigin(),
hasSubscription: hasSubscription,
app: app,
updateInfo: info,
changelogHTML: converter.makeHtml(info.manifest.changelog),
cloudronName: cloudronName,
cloudronAvatarUrl: config.adminOrigin() + '/api/v1/cloudron/avatar'
};
var templateDataText = JSON.parse(JSON.stringify(templateData));
templateDataText.format = 'text';
var templateDataText = JSON.parse(JSON.stringify(templateData));
templateDataText.format = 'text';
var templateDataHTML = JSON.parse(JSON.stringify(templateData));
templateDataHTML.format = 'html';
var templateDataHTML = JSON.parse(JSON.stringify(templateData));
templateDataHTML.format = 'html';
var mailOptions = {
from: mailConfig.notificationFrom,
to: mailConfig.adminEmails.join(', '),
subject: util.format('App %s has a new update available', app.fqdn),
text: render('app_update_available.ejs', templateDataText),
html: render('app_update_available.ejs', templateDataHTML)
};
var mailOptions = {
from: mailConfig().from,
to: adminEmails.join(', '),
subject: util.format('App %s has a new update available', app.fqdn),
text: render('app_update_available.ejs', templateDataText),
html: render('app_update_available.ejs', templateDataHTML)
};
enqueue(mailOptions);
});
enqueue(mailOptions);
});
}
function sendDigest(info) {
assert.strictEqual(typeof info, 'object');
getAdminEmails(function (error, adminEmails) {
if (error) return debug('Error getting admins', error);
getMailConfig(function (error, mailConfig) {
if (error) return debug('Error getting mail details:', error);
settings.getCloudronName(function (error, cloudronName) {
if (error) {
debug(error);
cloudronName = 'Cloudron';
}
var templateData = {
webadminUrl: config.adminOrigin(),
cloudronName: mailConfig.cloudronName,
cloudronAvatarUrl: config.adminOrigin() + '/api/v1/cloudron/avatar',
info: info
};
var templateData = {
webadminUrl: config.adminOrigin(),
cloudronName: cloudronName,
cloudronAvatarUrl: config.adminOrigin() + '/api/v1/cloudron/avatar',
info: info
};
var templateDataText = JSON.parse(JSON.stringify(templateData));
templateDataText.format = 'text';
var templateDataText = JSON.parse(JSON.stringify(templateData));
templateDataText.format = 'text';
var templateDataHTML = JSON.parse(JSON.stringify(templateData));
templateDataHTML.format = 'html';
var templateDataHTML = JSON.parse(JSON.stringify(templateData));
templateDataHTML.format = 'html';
var mailOptions = {
from: mailConfig.notificationFrom,
to: mailConfig.adminEmails.join(', '),
subject: util.format('[%s] Cloudron - Weekly activity digest', mailConfig.cloudronName),
text: render('digest.ejs', templateDataText),
html: render('digest.ejs', templateDataHTML)
};
var mailOptions = {
from: mailConfig().from,
to: adminEmails.join(', '),
subject: util.format('[%s] Cloudron - Weekly activity digest', cloudronName),
text: render('digest.ejs', templateDataText),
html: render('digest.ejs', templateDataHTML)
};
enqueue(mailOptions);
});
enqueue(mailOptions);
});
}
function outOfDiskSpace(message) {
assert.strictEqual(typeof message, 'string');
getAdminEmails(function (error, adminEmails) {
if (error) return debug('Error getting admins', error);
getMailConfig(function (error, mailConfig) {
if (error) return debug('Error getting mail details:', error);
settings.getCloudronName(function (error, cloudronName) {
if (error) {
debug(error);
cloudronName = 'Cloudron';
}
var mailOptions = {
from: mailConfig.notificationFrom,
to: config.provider() === 'caas' ? 'support@cloudron.io' : mailConfig.adminEmails.join(', '),
subject: util.format('[%s] Out of disk space alert', mailConfig.cloudronName),
text: render('out_of_disk_space.ejs', { cloudronName: mailConfig.cloudronName, message: message, format: 'text' })
};
var mailOptions = {
from: mailConfig().from,
to: config.provider() === 'caas' ? 'support@cloudron.io' : adminEmails.join(', '),
subject: util.format('[%s] Out of disk space alert', cloudronName),
text: render('out_of_disk_space.ejs', { cloudronName: cloudronName, message: message, format: 'text' })
};
sendMails([ mailOptions ]);
});
sendMails([ mailOptions ]);
});
}
function backupFailed(error) {
var message = splatchError(error);
getAdminEmails(function (error, adminEmails) {
if (error) return debug('Error getting admins', error);
getMailConfig(function (error, mailConfig) {
if (error) return debug('Error getting mail details:', error);
settings.getCloudronName(function (error, cloudronName) {
if (error) {
debug(error);
cloudronName = 'Cloudron';
}
var mailOptions = {
from: mailConfig.notificationFrom,
to: config.provider() === 'caas' ? 'support@cloudron.io' : mailConfig.adminEmails.join(', '),
subject: util.format('[%s] Failed to backup', mailConfig.cloudronName),
text: render('backup_failed.ejs', { cloudronName: mailConfig.cloudronName, message: message, format: 'text' })
};
var mailOptions = {
from: mailConfig().from,
to: config.provider() === 'caas' ? 'support@cloudron.io' : adminEmails.join(', '),
subject: util.format('[%s] Failed to backup', cloudronName),
text: render('backup_failed.ejs', { cloudronName: cloudronName, message: message, format: 'text' })
};
enqueue(mailOptions);
});
enqueue(mailOptions);
});
}
@@ -512,12 +475,12 @@ function certificateRenewalError(domain, message) {
assert.strictEqual(typeof domain, 'string');
assert.strictEqual(typeof message, 'string');
getAdminEmails(function (error, adminEmails) {
if (error) return debug('Error getting admins', error);
getMailConfig(function (error, mailConfig) {
if (error) return debug('Error getting mail details:', error);
var mailOptions = {
from: mailConfig().from,
to: config.provider() === 'caas' ? 'support@cloudron.io' : adminEmails.join(', '),
from: mailConfig.notificationFrom,
to: config.provider() === 'caas' ? 'support@cloudron.io' : mailConfig.adminEmails.join(', '),
subject: util.format('[%s] Certificate renewal error', domain),
text: render('certificate_renewal_error.ejs', { domain: domain, message: message, format: 'text' })
};
@@ -530,24 +493,17 @@ function oomEvent(program, context) {
assert.strictEqual(typeof program, 'string');
assert.strictEqual(typeof context, 'string');
getAdminEmails(function (error, adminEmails) {
if (error) return debug('Error getting admins', error);
getMailConfig(function (error, mailConfig) {
if (error) return debug('Error getting mail details:', error);
settings.getCloudronName(function (error, cloudronName) {
if (error) {
debug(error);
cloudronName = 'Cloudron';
}
var mailOptions = {
from: mailConfig.notificationFrom,
to: config.provider() === 'caas' ? 'support@cloudron.io' : mailConfig.adminEmails.join(', '),
subject: util.format('[%s] %s exited unexpectedly', mailConfig.cloudronName, program),
text: render('oom_event.ejs', { cloudronName: mailConfig.cloudronName, program: program, context: context, format: 'text' })
};
var mailOptions = {
from: mailConfig().from,
to: config.provider() === 'caas' ? 'support@cloudron.io' : adminEmails.join(', '),
subject: util.format('[%s] %s exited unexpectedly', cloudronName, program),
text: render('oom_event.ejs', { cloudronName: cloudronName, program: program, context: context, format: 'text' })
};
sendMails([ mailOptions ]);
});
sendMails([ mailOptions ]);
});
}
@@ -566,8 +522,9 @@ function unexpectedExit(program, context, callback) {
cloudronName = 'Cloudron';
}
// FIXME which domain should we use here if we can't contact the db??
var mailOptions = {
from: mailConfig().from,
from: '"Cloudron" <no-reply@' + config.fqdn() + '>',
to: 'support@cloudron.io',
subject: util.format('[%s] %s exited unexpectedly', cloudronName, program),
text: render('unexpected_exit.ejs', { cloudronName: cloudronName, program: program, context: context, format: 'text' })
@@ -580,17 +537,14 @@ function unexpectedExit(program, context, callback) {
function sendTestMail(email) {
assert.strictEqual(typeof email, 'string');
settings.getCloudronName(function (error, cloudronName) {
if (error) {
debug(error);
cloudronName = 'Cloudron';
}
getMailConfig(function (error, mailConfig) {
if (error) return debug('Error getting mail details:', error);
var mailOptions = {
from: mailConfig().from,
from: mailConfig.notificationFrom,
to: email,
subject: util.format('Test Email from %s', cloudronName),
text: render('test.ejs', { cloudronName: cloudronName, format: 'text'})
subject: util.format('Test Email from %s', mailConfig.cloudronName),
text: render('test.ejs', { cloudronName: mailConfig.cloudronName, format: 'text'})
};
enqueue(mailOptions);