mirror of
https://github.com/Unleash/unleash.git
synced 2024-10-18 20:09:08 +02:00
bb9ae03b27
This reverts commit 8f1a5f5a64
.
227 lines
6.7 KiB
TypeScript
227 lines
6.7 KiB
TypeScript
import { createTransport, Transporter } from 'nodemailer';
|
|
import Mustache from 'mustache';
|
|
import path from 'path';
|
|
import { readFileSync, existsSync } from 'fs';
|
|
import { Logger, LogProvider } from '../logger';
|
|
import NotFoundError from '../error/notfound-error';
|
|
import { IEmailOption } from '../types/option';
|
|
|
|
export interface IAuthOptions {
|
|
user: string;
|
|
pass: string;
|
|
}
|
|
|
|
export enum TemplateFormat {
|
|
HTML = 'html',
|
|
PLAIN = 'plain',
|
|
}
|
|
|
|
export enum TransporterType {
|
|
SMTP = 'smtp',
|
|
JSON = 'json',
|
|
}
|
|
|
|
export interface IEmailOptions {
|
|
host: string;
|
|
port: number;
|
|
secure: boolean;
|
|
sender: string;
|
|
auth: IAuthOptions;
|
|
transporterType: TransporterType;
|
|
}
|
|
|
|
export interface IEmailEnvelope {
|
|
from: string;
|
|
to: string;
|
|
subject: string;
|
|
html: string;
|
|
text: string;
|
|
}
|
|
|
|
const RESET_MAIL_SUBJECT = 'Unleash - Reset your password';
|
|
const GETTING_STARTED_SUBJECT = 'Welcome to Unleash';
|
|
|
|
export const MAIL_ACCEPTED = '250 Accepted';
|
|
|
|
export class EmailService {
|
|
private logger: Logger;
|
|
|
|
private readonly mailer?: Transporter;
|
|
|
|
private readonly sender: string;
|
|
|
|
constructor(email: IEmailOption, getLogger: LogProvider) {
|
|
this.logger = getLogger('services/email-service.ts');
|
|
if (email && email.host) {
|
|
this.sender = email.sender;
|
|
if (email.host === 'test') {
|
|
this.mailer = createTransport({ jsonTransport: true });
|
|
} else {
|
|
const connectionString = `${email.smtpuser}:${email.smtppass}@${email.host}:${email.port}`;
|
|
this.mailer = email.secure
|
|
? createTransport(`smtps://${connectionString}`)
|
|
: createTransport(`smtp://${connectionString}`);
|
|
}
|
|
this.logger.info(
|
|
`Initialized transport to ${email.host} on port ${email.port} with user: ${email.smtpuser}`,
|
|
);
|
|
} else {
|
|
this.sender = 'not-configured';
|
|
this.mailer = undefined;
|
|
}
|
|
}
|
|
|
|
async sendResetMail(
|
|
name: string,
|
|
recipient: string,
|
|
resetLink: string,
|
|
): Promise<IEmailEnvelope> {
|
|
if (this.configured()) {
|
|
const year = new Date().getFullYear();
|
|
const bodyHtml = await this.compileTemplate(
|
|
'reset-password',
|
|
TemplateFormat.HTML,
|
|
{
|
|
resetLink,
|
|
name,
|
|
year,
|
|
},
|
|
);
|
|
const bodyText = await this.compileTemplate(
|
|
'reset-password',
|
|
TemplateFormat.PLAIN,
|
|
{
|
|
resetLink,
|
|
name,
|
|
year,
|
|
},
|
|
);
|
|
const email = {
|
|
from: this.sender,
|
|
to: recipient,
|
|
subject: RESET_MAIL_SUBJECT,
|
|
html: bodyHtml,
|
|
text: bodyText,
|
|
};
|
|
process.nextTick(() => {
|
|
this.mailer.sendMail(email).then(
|
|
() =>
|
|
this.logger.info(
|
|
'Successfully sent reset-password email',
|
|
),
|
|
(e) =>
|
|
this.logger.warn(
|
|
'Failed to send reset-password email',
|
|
e,
|
|
),
|
|
);
|
|
});
|
|
return Promise.resolve(email);
|
|
}
|
|
return new Promise((res) => {
|
|
this.logger.warn(
|
|
'No mailer is configured. Please read the docs on how to configure an emailservice',
|
|
);
|
|
res({
|
|
from: this.sender,
|
|
to: recipient,
|
|
subject: RESET_MAIL_SUBJECT,
|
|
html: '',
|
|
text: '',
|
|
});
|
|
});
|
|
}
|
|
|
|
async sendGettingStartedMail(
|
|
name: string,
|
|
recipient: string,
|
|
passwordLink: string,
|
|
): Promise<IEmailEnvelope> {
|
|
if (this.configured()) {
|
|
const year = new Date().getFullYear();
|
|
const context = { passwordLink, name, year };
|
|
const bodyHtml = await this.compileTemplate(
|
|
'getting-started',
|
|
TemplateFormat.HTML,
|
|
context,
|
|
);
|
|
const bodyText = await this.compileTemplate(
|
|
'getting-started',
|
|
TemplateFormat.PLAIN,
|
|
context,
|
|
);
|
|
const email = {
|
|
from: this.sender,
|
|
to: recipient,
|
|
subject: GETTING_STARTED_SUBJECT,
|
|
html: bodyHtml,
|
|
text: bodyText,
|
|
};
|
|
process.nextTick(() => {
|
|
this.mailer.sendMail(email).then(
|
|
() =>
|
|
this.logger.info(
|
|
'Successfully sent getting started email',
|
|
),
|
|
(e) =>
|
|
this.logger.warn(
|
|
'Failed to send getting started email',
|
|
e,
|
|
),
|
|
);
|
|
});
|
|
return Promise.resolve(email);
|
|
}
|
|
return new Promise((res) => {
|
|
this.logger.warn(
|
|
'No mailer is configured. Please read the docs on how to configure an EmailService',
|
|
);
|
|
res({
|
|
from: this.sender,
|
|
to: recipient,
|
|
subject: GETTING_STARTED_SUBJECT,
|
|
html: '',
|
|
text: '',
|
|
});
|
|
});
|
|
}
|
|
|
|
isEnabled(): boolean {
|
|
return this.mailer !== undefined;
|
|
}
|
|
|
|
private async compileTemplate(
|
|
templateName: string,
|
|
format: TemplateFormat,
|
|
context: any,
|
|
): Promise<string> {
|
|
try {
|
|
const template = this.resolveTemplate(templateName, format);
|
|
return await Promise.resolve(Mustache.render(template, context));
|
|
} catch (e) {
|
|
this.logger.info(`Could not find template ${templateName}`);
|
|
return Promise.reject(e);
|
|
}
|
|
}
|
|
|
|
private resolveTemplate(
|
|
templateName: string,
|
|
format: TemplateFormat,
|
|
): string {
|
|
const topPath = path.resolve(__dirname, '../../mailtemplates');
|
|
const template = path.join(
|
|
topPath,
|
|
templateName,
|
|
`${templateName}.${format}.mustache`,
|
|
);
|
|
if (existsSync(template)) {
|
|
return readFileSync(template, 'utf-8');
|
|
}
|
|
throw new NotFoundError('Could not find template');
|
|
}
|
|
|
|
configured(): boolean {
|
|
return this.sender !== 'not-configured' && this.mailer !== undefined;
|
|
}
|
|
}
|