mirror of
https://github.com/wassname/talk.git
synced 2026-07-08 21:51:40 +08:00
148 lines
3.5 KiB
JavaScript
148 lines
3.5 KiB
JavaScript
const { task } = require('../services/mailer');
|
|
const nodemailer = require('nodemailer');
|
|
const { createLogger } = require('../services/logging');
|
|
const logger = createLogger('jobs:mailer');
|
|
const Context = require('../graph/context');
|
|
const { get } = require('lodash');
|
|
const {
|
|
SMTP_HOST,
|
|
SMTP_USERNAME,
|
|
SMTP_PORT,
|
|
SMTP_PASSWORD,
|
|
SMTP_FROM_ADDRESS,
|
|
} = require('../config');
|
|
const { ErrMissingEmail } = require('../errors');
|
|
|
|
// parseSMTPPort will return the port for SMTP.
|
|
const parseSMTPPort = () => {
|
|
if (!SMTP_PORT) {
|
|
return 25;
|
|
}
|
|
|
|
try {
|
|
return parseInt(SMTP_PORT);
|
|
} catch (e) {
|
|
throw new Error('TALK_SMTP_PORT is not an integer');
|
|
}
|
|
};
|
|
|
|
// createTransport will create a new transport.
|
|
const createTransport = () => {
|
|
const options = {
|
|
host: SMTP_HOST,
|
|
};
|
|
|
|
if (SMTP_USERNAME && SMTP_PASSWORD) {
|
|
options.auth = {
|
|
user: SMTP_USERNAME,
|
|
pass: SMTP_PASSWORD,
|
|
};
|
|
}
|
|
|
|
// Get the SMTP port.
|
|
options.port = parseSMTPPort();
|
|
|
|
return nodemailer.createTransport(options);
|
|
};
|
|
|
|
// sharedTransport is the transport singleton.
|
|
let sharedTransport;
|
|
|
|
// getTransport will retrieve the mailer transport singleton.
|
|
const getTransport = () => {
|
|
if (sharedTransport) {
|
|
return sharedTransport;
|
|
}
|
|
|
|
// enabled is true when the required configuration is available. When testing
|
|
// is enabled, we will be simulating that emails are being sent, because in a
|
|
// production system, emails should and would be sent.
|
|
|
|
// If the transport details aren't available, we will return null as the
|
|
// transport.
|
|
if (!SMTP_HOST || !SMTP_FROM_ADDRESS) {
|
|
return null;
|
|
}
|
|
|
|
// Create the transport.
|
|
sharedTransport = createTransport();
|
|
|
|
return sharedTransport;
|
|
};
|
|
|
|
// getEmailAddress will retrieve the email address to send the message to from
|
|
// the job data.
|
|
const getEmailAddress = async ({ email, user }) => {
|
|
// If the message has a specific email already to sent it to, just assign
|
|
// that to the message. If the email does not have an email, and instead has
|
|
// a user id, then we should lookup the user with the graph and get their
|
|
// email.
|
|
if (email) {
|
|
return email;
|
|
} else {
|
|
// Get the user to send the message to.
|
|
const ctx = Context.forSystem();
|
|
|
|
const { data, errors } = await ctx.graphql(
|
|
`
|
|
query GetUserEmail($user: ID!) {
|
|
user(id: $user) {
|
|
email
|
|
}
|
|
}
|
|
`,
|
|
{ user }
|
|
);
|
|
if (errors) {
|
|
throw errors;
|
|
}
|
|
|
|
const email = get(data, 'user.email');
|
|
if (!email) {
|
|
throw new ErrMissingEmail();
|
|
}
|
|
|
|
return email;
|
|
}
|
|
};
|
|
|
|
// processJob will handle new jobs sent via this queue.
|
|
const processJob = transport => async ({ id, data }, done) => {
|
|
const { message } = data;
|
|
|
|
// Get the email address from the job data.
|
|
message.to = await getEmailAddress(data);
|
|
|
|
const log = logger.child({ jobID: id });
|
|
log.info('Starting to send mail');
|
|
|
|
// Actually send the email.
|
|
transport.sendMail(message, err => {
|
|
if (err) {
|
|
logger.error({ err }, 'Failed to send mail');
|
|
return done(err);
|
|
}
|
|
|
|
logger.info('Finished sending mail');
|
|
return done();
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Start the queue processor for the mailer job.
|
|
*/
|
|
module.exports = () => {
|
|
// Get a transport.
|
|
const transport = getTransport();
|
|
if (transport === null) {
|
|
logger.warn(
|
|
'Sending email is not enabled because required configuration is not available'
|
|
);
|
|
return;
|
|
}
|
|
|
|
logger.info({ taskName: task.name }, 'Now processing jobs');
|
|
|
|
return task.process(processJob(transport));
|
|
};
|