2020-04-22 15:52:17 +02:00
|
|
|
import ApplicationComponent from "../ApplicationComponent";
|
2020-07-11 11:46:16 +02:00
|
|
|
import {Express} from "express";
|
2020-07-15 15:06:13 +02:00
|
|
|
import config from "config";
|
|
|
|
import SecurityError from "../SecurityError";
|
2021-04-28 14:53:46 +02:00
|
|
|
import nodemailer, {SentMessageInfo, Transporter} from "nodemailer";
|
|
|
|
import MailError from "../mail/MailError";
|
|
|
|
import util from "util";
|
|
|
|
import {logger} from "../Logger";
|
|
|
|
import Controller from "../Controller";
|
|
|
|
import Mail from "../mail/Mail";
|
|
|
|
import MailViewEngine from "../frontend/MailViewEngine";
|
|
|
|
import ViewEngine from "../frontend/ViewEngine";
|
2020-04-22 15:52:17 +02:00
|
|
|
|
2020-09-25 22:03:22 +02:00
|
|
|
export default class MailComponent extends ApplicationComponent {
|
2021-04-28 14:53:46 +02:00
|
|
|
private transporter?: Transporter;
|
|
|
|
|
|
|
|
public constructor(
|
|
|
|
private readonly viewEngine: MailViewEngine,
|
|
|
|
) {
|
|
|
|
super();
|
|
|
|
}
|
2020-07-15 15:06:13 +02:00
|
|
|
|
|
|
|
public async checkSecuritySettings(): Promise<void> {
|
2020-07-20 11:29:10 +02:00
|
|
|
if (!config.get<boolean>('mail.secure')) {
|
|
|
|
throw new SecurityError('Cannot set mail.secure (starttls) to false');
|
|
|
|
}
|
2020-07-15 15:06:13 +02:00
|
|
|
if (config.get<boolean>('mail.allow_invalid_tls')) {
|
2020-07-20 11:29:10 +02:00
|
|
|
throw new SecurityError('Cannot set mail.allow_invalid_tls (ignore tls failure) to true');
|
2020-07-15 15:06:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-28 14:53:46 +02:00
|
|
|
public async start(app: Express): Promise<void> {
|
|
|
|
await this.prepare('Mail connection', async () => {
|
|
|
|
const transporter = nodemailer.createTransport({
|
|
|
|
host: config.get('mail.host'),
|
|
|
|
port: config.get('mail.port'),
|
|
|
|
requireTLS: config.get('mail.secure'), // STARTTLS
|
|
|
|
auth: {
|
|
|
|
user: config.get('mail.username'),
|
|
|
|
pass: config.get('mail.password'),
|
|
|
|
},
|
|
|
|
tls: {
|
|
|
|
rejectUnauthorized: !config.get('mail.allow_invalid_tls'),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
try {
|
|
|
|
await util.promisify(transporter.verify)();
|
|
|
|
this.transporter = transporter;
|
|
|
|
} catch (e) {
|
|
|
|
throw new MailError('Connection to mail service unsuccessful.', e);
|
|
|
|
}
|
|
|
|
|
|
|
|
logger.info(`Mail ready to be distributed via ${config.get('mail.host')}:${config.get('mail.port')}`);
|
|
|
|
});
|
|
|
|
|
|
|
|
await this.viewEngine.setup(app, false);
|
2020-04-22 15:52:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public async stop(): Promise<void> {
|
2021-04-28 14:53:46 +02:00
|
|
|
if (this.transporter) {
|
|
|
|
this.transporter.close();
|
|
|
|
this.transporter = undefined;
|
|
|
|
}
|
|
|
|
await this.viewEngine.stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
public async sendMail(mail: Mail, ...to: string[]): Promise<SentMessageInfo[]> {
|
|
|
|
if (to.length === 0) throw new Error('Cannot send an email to recipient. (to is empty)');
|
|
|
|
|
|
|
|
const results = [];
|
|
|
|
|
|
|
|
for (const destEmail of to) {
|
|
|
|
const template = mail.getTemplate();
|
|
|
|
const locals = mail.getData();
|
|
|
|
const options = mail.getOptions();
|
|
|
|
|
|
|
|
// Reset options
|
|
|
|
options.html = options.text = undefined;
|
|
|
|
|
|
|
|
// Set options
|
|
|
|
options.to = destEmail;
|
|
|
|
options.from = {
|
|
|
|
name: config.get('mail.from_name'),
|
|
|
|
address: config.get('mail.from'),
|
|
|
|
};
|
|
|
|
|
|
|
|
// Set locals
|
|
|
|
locals.mail_subject = options.subject;
|
|
|
|
locals.mail_to = options.to;
|
|
|
|
locals.mail_link = config.get<string>('public_url') +
|
|
|
|
Controller.route('mail', [template.template], locals);
|
|
|
|
Object.assign(locals, ViewEngine.getGlobals());
|
|
|
|
|
|
|
|
// Log
|
|
|
|
logger.debug(`Send mail from ${options.from.address} to ${options.to}`);
|
|
|
|
|
|
|
|
// Render email
|
|
|
|
|
|
|
|
options.html = await this.viewEngine.render('mails/' + template.template + '.mnjk', locals, false);
|
|
|
|
options.text = await this.viewEngine.render('mails/' + template.template + '.mnjk', locals, true);
|
|
|
|
|
|
|
|
// Send email
|
|
|
|
results.push(await this.getTransporter().sendMail(options));
|
|
|
|
}
|
|
|
|
|
|
|
|
return results;
|
2020-04-22 15:52:17 +02:00
|
|
|
}
|
|
|
|
|
2021-04-28 14:53:46 +02:00
|
|
|
private getTransporter(): Transporter {
|
|
|
|
if (!this.transporter) throw new MailError('Mail system was not prepared.');
|
|
|
|
return this.transporter;
|
|
|
|
}
|
2020-09-25 23:42:15 +02:00
|
|
|
}
|