diff --git a/core/server/api/authentication.js b/core/server/api/authentication.js index 502a41abfb..9c99d687d6 100644 --- a/core/server/api/authentication.js +++ b/core/server/api/authentication.js @@ -532,13 +532,11 @@ authentication = { }] }; - mailAPI.send(payload, {context: {internal: true}}).catch(function (error) { - logging.error(new errors.EmailError({ - err: error, - context: i18n.t('errors.api.authentication.unableToSendWelcomeEmail'), - help: i18n.t('errors.api.authentication.checkEmailConfigInstructions', {url: 'http://docs.ghost.org/v1/docs/mail-config'}) - })); - }); + mailAPI.send(payload, {context: {internal: true}}) + .catch(function (err) { + err.context = i18n.t('errors.api.authentication.unableToSendWelcomeEmail'); + logging.error(err); + }); }) .return(setupUser); } diff --git a/core/server/api/mail.js b/core/server/api/mail.js index 625a0ef01c..61e1c35396 100644 --- a/core/server/api/mail.js +++ b/core/server/api/mail.js @@ -5,7 +5,6 @@ var Promise = require('bluebird'), pipeline = require('../utils/pipeline'), apiUtils = require('./utils'), models = require('../models'), - errors = require('../errors'), i18n = require('../i18n'), mail = require('../mail'), notificationsAPI = require('./notifications'), @@ -36,7 +35,7 @@ function sendMail(object) { ); } - return Promise.reject(new errors.EmailError({err: err})); + return Promise.reject(err); }); } diff --git a/core/server/mail/GhostMailer.js b/core/server/mail/GhostMailer.js index db7319df2b..9d9b73c3bf 100644 --- a/core/server/mail/GhostMailer.js +++ b/core/server/mail/GhostMailer.js @@ -1,12 +1,13 @@ // # Mail // Handles sending email for Ghost -var _ = require('lodash'), - Promise = require('bluebird'), - validator = require('validator'), - config = require('../config'), +var _ = require('lodash'), + Promise = require('bluebird'), + validator = require('validator'), + config = require('../config'), + errors = require('../errors'), settingsCache = require('../settings/cache'), - i18n = require('../i18n'), - utils = require('../utils'); + i18n = require('../i18n'), + utils = require('../utils'); function GhostMailer() { var nodemailer = require('nodemailer'), @@ -47,14 +48,19 @@ GhostMailer.prototype.getDomain = function () { // This assumes that api.settings.read('email') was already done on the API level GhostMailer.prototype.send = function (message) { var self = this, - to; + to, + help = i18n.t('errors.api.authentication.checkEmailConfigInstructions', {url: 'http://docs.ghost.org/v1/docs/mail-config'}), + errorMessage = i18n.t('errors.mail.failedSendingEmail.error'); // important to clone message as we modify it message = _.clone(message) || {}; to = message.to || false; if (!(message && message.subject && message.html && message.to)) { - return Promise.reject(new Error(i18n.t('errors.mail.incompleteMessageData.error'))); + return Promise.reject(new errors.EmailError({ + message: i18n.t('errors.mail.incompleteMessageData.error'), + help: help + })); } message = _.extend(message, { @@ -65,9 +71,15 @@ GhostMailer.prototype.send = function (message) { }); return new Promise(function (resolve, reject) { - self.transport.sendMail(message, function (error, response) { - if (error) { - return reject(new Error(error)); + self.transport.sendMail(message, function (err, response) { + if (err) { + errorMessage += i18n.t('errors.mail.reason', {reason: err.message || err}); + + return reject(new errors.EmailError({ + message: errorMessage, + err: err, + help: help + })); } if (self.transport.transportType !== 'DIRECT') { @@ -75,23 +87,25 @@ GhostMailer.prototype.send = function (message) { } response.statusHandler.once('failed', function (data) { - var reason = i18n.t('errors.mail.failedSendingEmail.error'); - if (data.error && data.error.errno === 'ENOTFOUND') { - reason += i18n.t('errors.mail.noMailServerAtAddress.error', {domain: data.domain}); + errorMessage += i18n.t('errors.mail.noMailServerAtAddress.error', {domain: data.domain}); } - reason += '.'; - return reject(new Error(reason)); + + return reject(new errors.EmailError({ + message: errorMessage, + help: help + })); }); response.statusHandler.once('requeue', function (data) { - var errorMessage = i18n.t('errors.mail.messageNotSent.error'); - if (data.error && data.error.message) { - errorMessage += i18n.t('errors.general.moreInfo', {info: data.error.message}); + errorMessage += i18n.t('errors.mail.reason', {reason: data.error.message}); } - return reject(new Error(errorMessage)); + return reject(new errors.EmailError({ + message: errorMessage, + help: help + })); }); response.statusHandler.once('sent', function () { diff --git a/core/server/translations/en.json b/core/server/translations/en.json index ebe54875f6..4e9aaf9ba7 100644 --- a/core/server/translations/en.json +++ b/core/server/translations/en.json @@ -167,7 +167,6 @@ }, "general": { "maintenance": "Ghost is currently undergoing maintenance, please wait a moment then retry.", - "moreInfo": "\nMore info: {info}", "requiredOnFuture": "This will be required in future. Please see {link}", "internalError": "Something went wrong." }, @@ -185,17 +184,15 @@ }, "mail": { "incompleteMessageData": { - "error": "Error: Incomplete message data." + "error": "Incomplete message data." }, "failedSendingEmail": { - "error": "Error: Failed to send email" + "error": "Failed to send email." }, "noMailServerAtAddress": { - "error": " - no mail server found at {domain}" + "error": " No mail server found at {domain}." }, - "messageNotSent": { - "error": "Error: Message could not be sent" - } + "reason": " Reason: {reason}." }, "models": { "subscriber": { diff --git a/core/test/unit/mail/GhostMailer_spec.js b/core/test/unit/mail/GhostMailer_spec.js index 5647ee9dd0..6c4d4cec4a 100644 --- a/core/test/unit/mail/GhostMailer_spec.js +++ b/core/test/unit/mail/GhostMailer_spec.js @@ -96,7 +96,7 @@ describe('Mail: Ghostmailer', function () { mailer.send(mailDataNoServer).then(function () { done(new Error('Stub did not error')); }).catch(function (error) { - error.message.should.eql('Error: Stub made a boo boo :('); + error.message.should.containEql('Stub made a boo boo :('); done(); }).catch(done); }); @@ -113,7 +113,7 @@ describe('Mail: Ghostmailer', function () { descriptors.forEach(function (d) { d.isFulfilled().should.be.false(); d.reason().should.be.an.instanceOf(Error); - d.reason().message.should.eql('Error: Incomplete message data.'); + d.reason().message.should.eql('Incomplete message data.'); }); done(); }).catch(done); @@ -136,7 +136,7 @@ describe('Mail: Ghostmailer', function () { mailer.send(mailDataNoDomain).then(function () { done(new Error('Error message not shown.')); }, function (error) { - error.message.should.startWith('Error: Failed to send email'); + error.message.should.startWith('Failed to send email.'); done(); }).catch(done); }); @@ -147,7 +147,7 @@ describe('Mail: Ghostmailer', function () { mailer.send(mailDataNoServer).then(function () { done(new Error('Error message not shown.')); }, function (error) { - error.message.should.eql('Error: Failed to send email.'); + error.message.should.eql('Failed to send email.'); done(); }).catch(done); }); @@ -158,7 +158,7 @@ describe('Mail: Ghostmailer', function () { mailer.send(mailDataIncomplete).then(function () { done(new Error('Error message not shown.')); }, function (error) { - error.message.should.eql('Error: Incomplete message data.'); + error.message.should.eql('Incomplete message data.'); done(); }).catch(done); });