2021-04-23 14:49:47 +02:00
|
|
|
const nodemailer = require("nodemailer")
|
2021-04-27 18:29:05 +02:00
|
|
|
const CouchDB = require("../db")
|
|
|
|
const { StaticDatabases, determineScopedConfig } = require("@budibase/auth").db
|
2021-04-27 18:30:19 +02:00
|
|
|
const { EmailTemplatePurpose, TemplateTypes, Configs } = require("../constants")
|
2021-04-27 18:29:05 +02:00
|
|
|
const { getTemplateByPurpose } = require("../constants/templates")
|
|
|
|
const { getSettingsTemplateContext } = require("./templates")
|
|
|
|
const { processString } = require("@budibase/string-templates")
|
2021-04-23 14:49:47 +02:00
|
|
|
|
2021-04-27 18:29:05 +02:00
|
|
|
const GLOBAL_DB = StaticDatabases.GLOBAL.name
|
|
|
|
const TYPE = TemplateTypes.EMAIL
|
|
|
|
|
|
|
|
const FULL_EMAIL_PURPOSES = [
|
|
|
|
EmailTemplatePurpose.INVITATION,
|
|
|
|
EmailTemplatePurpose.PASSWORD_RECOVERY,
|
|
|
|
EmailTemplatePurpose.WELCOME,
|
|
|
|
]
|
|
|
|
|
|
|
|
function createSMTPTransport(config) {
|
2021-04-23 14:49:47 +02:00
|
|
|
const options = {
|
|
|
|
port: config.port,
|
|
|
|
host: config.host,
|
|
|
|
secure: config.secure || false,
|
|
|
|
auth: config.auth,
|
|
|
|
}
|
|
|
|
if (config.selfSigned) {
|
|
|
|
options.tls = {
|
|
|
|
rejectUnauthorized: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nodemailer.createTransport(options)
|
|
|
|
}
|
|
|
|
|
2021-04-27 18:29:05 +02:00
|
|
|
async function buildEmail(purpose, email, user) {
|
|
|
|
// this isn't a full email
|
|
|
|
if (FULL_EMAIL_PURPOSES.indexOf(purpose) === -1) {
|
|
|
|
throw `Unable to build an email of type ${purpose}`
|
|
|
|
}
|
|
|
|
let [base, styles, body] = await Promise.all([
|
|
|
|
getTemplateByPurpose(TYPE, EmailTemplatePurpose.BASE),
|
|
|
|
getTemplateByPurpose(TYPE, EmailTemplatePurpose.STYLES),
|
|
|
|
getTemplateByPurpose(TYPE, purpose),
|
|
|
|
])
|
|
|
|
if (!base || !styles || !body) {
|
|
|
|
throw "Unable to build email, missing base components"
|
|
|
|
}
|
|
|
|
base = base.contents
|
|
|
|
styles = styles.contents
|
|
|
|
body = body.contents
|
|
|
|
|
|
|
|
// TODO: need to extend the context as much as possible
|
|
|
|
const context = {
|
|
|
|
...(await getSettingsTemplateContext()),
|
|
|
|
email,
|
|
|
|
user: user || {},
|
|
|
|
}
|
|
|
|
|
|
|
|
body = await processString(body, context)
|
|
|
|
styles = await processString(styles, context)
|
|
|
|
// this should now be the complete email HTML
|
|
|
|
return processString(base, {
|
|
|
|
...context,
|
|
|
|
styles,
|
|
|
|
body,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
exports.sendEmail = async (email, purpose, { groupId, userId }) => {
|
|
|
|
const db = new CouchDB(GLOBAL_DB)
|
|
|
|
const params = {
|
|
|
|
type: Configs.SMTP,
|
|
|
|
}
|
|
|
|
if (groupId) {
|
|
|
|
params.group = groupId
|
|
|
|
}
|
|
|
|
let user = {}
|
|
|
|
if (userId) {
|
|
|
|
user = db.get(userId)
|
|
|
|
}
|
|
|
|
const config = await determineScopedConfig(db, params)
|
|
|
|
if (!config) {
|
|
|
|
throw "Unable to find SMTP configuration"
|
|
|
|
}
|
|
|
|
const transport = createSMTPTransport(config)
|
|
|
|
const message = {
|
|
|
|
from: config.from,
|
|
|
|
subject: config.subject,
|
|
|
|
to: email,
|
|
|
|
html: await buildEmail(purpose, email, user),
|
|
|
|
}
|
|
|
|
return transport.sendMail(message)
|
|
|
|
}
|
|
|
|
|
2021-04-23 14:49:47 +02:00
|
|
|
exports.verifyConfig = async config => {
|
2021-04-27 18:29:05 +02:00
|
|
|
const transport = createSMTPTransport(config)
|
2021-04-23 14:49:47 +02:00
|
|
|
await transport.verify()
|
|
|
|
}
|