fxa-auth-server/mailer.js

175 строки
5.2 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var path = require('path')
var fs = require('fs')
var qs = require('querystring')
var nodemailer = require('nodemailer')
var P = require('./promise')
var handlebars = require("handlebars")
module.exports = function (config, i18n, log) {
function loadTemplate (name) {
return fs.readFileSync(path.join(config.templatePath, name))
}
// Make the 'gettext' function available in the templates.
handlebars.registerHelper('gettext', function(string) {
if (this.l10n) {
return this.l10n.gettext(string)
}
return string
})
// a map of all the different emails we send
var templates = {
verify: {
subject: 'Confirm email address for your Firefox Account',
text: loadTemplate('verify.txt'),
html: loadTemplate('verify.html')
},
reset: {
subject: 'Reset password for your Firefox Account',
text: loadTemplate('reset.txt'),
html: loadTemplate('reset.html')
}
}
// now turn file contents into compiled templates
Object.keys(templates).forEach(function(type) {
templates[type].text = handlebars.compile(templates[type].text.toString())
templates[type].html = handlebars.compile(templates[type].html.toString())
})
function Mailer(config) {
var options = {
host: config.host,
secureConnection: config.secure,
port: config.port
}
if (config.user && config.password) {
options.auth = {
user: config.user,
pass: config.password
}
}
this.mailer = nodemailer.createTransport('SMTP', options)
this.sender = config.sender
this.verificationUrl = config.verificationUrl
this.passwordResetUrl = config.passwordResetUrl
}
Mailer.prototype.stop = function () {
this.mailer.close()
}
Mailer.prototype.send = function (message) {
log.trace({ op: 'mailer.send', email: message && message.to })
var d = P.defer()
this.mailer.sendMail(
message,
function (err, status) {
log.trace(
{
op: 'mailer.send.1',
err: err && err.message,
status: status && status.message,
id: status && status.messageId
}
)
return err ? d.reject(err) : d.resolve(status)
}
)
return d.promise
}
// Sends a verification email to the user.
//
// - account : the account containing account.email and account.uid
// - code : the code which proves the user got the email
// - opts : object of options:
// - service : the service we came from
// - redirectTo : where to redirect the user once clicked
// - preferredLang : the preferred language of the user
Mailer.prototype.sendVerifyCode = function (account, code, opts) {
log.trace({ op: 'mailer.sendVerifyCode', email: account.email, uid: account.uid })
code = code.toString('hex')
opts = opts || {}
var template = templates.verify
var query = {
uid: account.uid.toString('hex'),
code: code
}
if (opts.service) { query.service = opts.service }
if (opts.redirectTo) { query.redirectTo = opts.redirectTo }
var link = this.verificationUrl + '?' + qs.stringify(query)
var values = {
l10n: i18n.localizationContext(opts.preferredLang),
link: link,
}
var message = {
sender: this.sender,
to: account.email,
subject: values.l10n.gettext(template.subject),
text: template.text(values),
html: template.html(values),
headers: {
'X-Uid': account.uid.toString('hex'),
'X-Verify-Code': code,
'X-Service-ID': opts.service,
'X-Link': link,
'Content-Language': opts.preferredLang || i18n.defaultLang
}
}
return this.send(message)
}
// Sends an account recovery email to the user.
//
// - token : the token containing token.email and token.data
// - code : the code which proves the user got the email
// - opts : object of options:
// - service : the service we came from
// - redirectTo : where to redirect the user once clicked
// - preferredLang : the preferred language of the user
Mailer.prototype.sendRecoveryCode = function (token, code, opts) {
log.trace({ op: 'mailer.sendRecoveryCode', email: token.email })
code = code.toString('hex')
opts = opts || {}
var template = templates.reset
var query = {
token: token.data.toString('hex'),
code: code,
email: token.email
}
if (opts.service) { query.service = opts.service }
if (opts.redirectTo) { query.redirectTo = opts.redirectTo }
var link = this.passwordResetUrl + '?' + qs.stringify(query)
var values = {
l10n: i18n.localizationContext(opts.preferredLang),
link: link,
code: code
}
var message = {
sender: this.sender,
to: token.email,
subject: values.l10n.gettext(template.subject),
text: template.text(values),
html: template.html(values),
headers: {
'X-Recovery-Code': code,
'X-Link': link,
'Content-Language': opts.preferredLang || i18n.defaultLang
}
}
return this.send(message)
}
return new Mailer(config)
}