You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
111 lines
3.2 KiB
111 lines
3.2 KiB
// email.js
|
|
// Copyright (C) 2021 Digital Telepresence, LLC
|
|
// License: Apache-2.0
|
|
|
|
'use strict';
|
|
|
|
const path = require('path');
|
|
const pug = require('pug');
|
|
|
|
const nodemailer = require('nodemailer');
|
|
|
|
const mongoose = require('mongoose');
|
|
const EmailBlacklist = mongoose.model('EmailBlacklist');
|
|
|
|
const disposableEmailDomains = require('disposable-email-provider-domains');
|
|
const emailValidator = require('email-validator');
|
|
const emailDomainCheck = require('email-domain-check');
|
|
|
|
const { SiteService } = require('../../lib/site-lib');
|
|
|
|
class EmailService extends SiteService {
|
|
|
|
constructor (dtp) {
|
|
super(dtp, module.exports);
|
|
}
|
|
|
|
async start ( ) {
|
|
await super.start();
|
|
|
|
if (process.env.DTP_EMAIL_ENABLED !== 'enabled') {
|
|
return;
|
|
}
|
|
|
|
const SMTP_PORT = parseInt(process.env.DTP_EMAIL_SMTP_PORT || '587', 10);
|
|
this.log.info('creating SMTP transport', {
|
|
host: process.env.DTP_EMAIL_SMTP_HOST,
|
|
port: SMTP_PORT,
|
|
});
|
|
this.transport = nodemailer.createTransport({
|
|
host: process.env.DTP_EMAIL_SMTP_HOST,
|
|
port: SMTP_PORT,
|
|
secure: process.env.DTP_EMAIL_SMTP_SECURE === 'enabled',
|
|
auth: {
|
|
user: process.env.DTP_EMAIL_SMTP_USER,
|
|
pass: process.env.DTP_EMAIL_SMTP_PASS,
|
|
},
|
|
pool: true,
|
|
maxConnections: parseInt(process.env.DTP_EMAIL_SMTP_POOL_MAX_CONN || '5', 10),
|
|
maxMessages: parseInt(process.env.DTP_EMAIL_SMTP_POOL_MAX_MSGS || '5', 10),
|
|
});
|
|
|
|
this.templates = {
|
|
html: {
|
|
welcome: pug.compileFile(path.join(this.dtp.config.root, 'app', 'templates', 'html', 'welcome.pug')),
|
|
},
|
|
text: {
|
|
welcome: pug.compileFile(path.join(this.dtp.config.root, 'app', 'templates', 'text', 'welcome.pug')),
|
|
},
|
|
};
|
|
}
|
|
|
|
async send (message) {
|
|
this.log.info('sending email', { to: message.to, subject: message.subject });
|
|
await this.transport.sendMail(message);
|
|
}
|
|
|
|
async checkEmailAddress (emailAddress) {
|
|
this.log.debug('validating email address', { emailAddress });
|
|
if (!emailValidator.validate(emailAddress)) {
|
|
throw new Error('Email address is invalid');
|
|
}
|
|
|
|
const domainCheck = await emailDomainCheck(emailAddress);
|
|
this.log.debug('email domain check', { domainCheck });
|
|
if (!domainCheck) {
|
|
throw new Error('Email address is invalid');
|
|
}
|
|
|
|
await this.isEmailBlacklisted(emailAddress);
|
|
}
|
|
|
|
async isEmailBlacklisted (emailAddress) {
|
|
emailAddress = emailAddress.toLowerCase().trim();
|
|
|
|
const domain = emailAddress.split('@')[1];
|
|
this.log.debug('checking email domain for blacklist', { domain });
|
|
if (disposableEmailDomains.domains.includes(domain)) {
|
|
this.log.alert('blacklisted email domain blocked', { emailAddress, domain });
|
|
throw new Error('Invalid email address');
|
|
}
|
|
|
|
const blacklistRecord = await EmailBlacklist.findOne({ email: emailAddress });
|
|
if (blacklistRecord) {
|
|
throw new Error('Email address has requested to not receive emails', { blacklistRecord });
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
async renderTemplate (templateId, templateType, message) {
|
|
return this.templates[templateType][templateId](message);
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
slug: 'email',
|
|
name: 'email',
|
|
create: (dtp) => {
|
|
return new EmailService(dtp);
|
|
},
|
|
}; |