@perfood/couch-auth
Version:
Easy and secure authentication for CouchDB/Cloudant. Based on SuperLogin, updated and rewritten in Typescript.
95 lines (94 loc) • 3.7 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Mailer = void 0;
const nodemailer_1 = __importDefault(require("nodemailer"));
const path_1 = require("path");
const template_utils_1 = require("./template-utils");
const util_1 = require("./util");
class Mailer {
constructor(config) {
this.config = config;
if (config.testMode?.noEmail) {
this.transporter = nodemailer_1.default.createTransport(require('nodemailer-stub-transport')());
}
else {
this.transporter = nodemailer_1.default.createTransport(config.mailer.transport ?? config.mailer.options);
}
}
/**
* Use the same nodemailer config that couch-auth uses to send out an email.
* Internally, `req` (the sent request), `user` (the sl-user doc) and `data`
* defined in the config are always available.
*
* @param templateId the entry under the `emails` property in the config
* @param recepient the recepient's email address
* @param data additional data directly passed to `nunjucks.render()`. Don't
* add anything called `data` in here!
*/
async sendEmail(templateId, recepient, data) {
// load the template and parse it
const templateConfig = this.config.emailTemplates.templates[templateId];
if (!templateConfig) {
return Promise.reject('No template entry for "' + templateId + '".');
}
const templateDirectory = this.config.emailTemplates.folder ?? (0, path_1.join)(__dirname, './templates/email');
let templates;
const templateData = {
subject: templateConfig.subject,
data: {
...this.config.emailTemplates.data,
...templateConfig.data
},
...data,
templateId
};
try {
templates = (0, template_utils_1.parseCompositeTemplate)(templateDirectory, templateId, templateData);
}
catch (error) {
templates = (0, template_utils_1.parseTemplatesDirectly)(templateDirectory, templateId, templateData);
if (!templates.html && !templates.text) {
return Promise.reject(`Could not parse ${templateId} in ${templateDirectory}. ` + error);
}
}
// form the email
let mailOptions = {
from: this.config.mailer.fromEmail,
to: recepient,
subject: templateConfig.subject,
...templates
};
if (this.config.mailer.messageConfig) {
mailOptions = { ...this.config.mailer.messageConfig, ...mailOptions };
}
if (this.config.testMode?.debugEmail) {
console.log(mailOptions);
}
// send the message
if (this.config.mailer.retryOnError) {
return this.sendMailWithBackoff(mailOptions, 0);
}
else {
return this.transporter.sendMail(mailOptions);
}
}
async sendMailWithBackoff(mailOptions, attempt) {
try {
return this.transporter.sendMail(mailOptions);
}
catch (error) {
attempt += 1;
if (attempt > this.config.mailer.retryOnError.maxRetries) {
throw error;
}
await (0, util_1.timeoutPromise)(1000 *
this.config.mailer.retryOnError.initialBackoffSeconds *
2 ** attempt);
return this.sendMailWithBackoff(mailOptions, attempt);
}
}
}
exports.Mailer = Mailer;