From 10dcb922f2f3541f3cd250bb65f93cbc8922d07f Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Mon, 1 Apr 2024 18:22:58 +0800 Subject: [PATCH] Enqueue confirmation email --- packages/api/src/jobs/send_email.ts | 26 ++++++++++++++++++++++++ packages/api/src/queue-processor.ts | 6 ++++++ packages/api/src/services/create_user.ts | 4 +--- packages/api/src/services/send_emails.ts | 20 ++++++++---------- packages/api/src/utils/createTask.ts | 22 ++++++++++++++++++++ 5 files changed, 63 insertions(+), 15 deletions(-) create mode 100644 packages/api/src/jobs/send_email.ts diff --git a/packages/api/src/jobs/send_email.ts b/packages/api/src/jobs/send_email.ts new file mode 100644 index 000000000..c104e8eb2 --- /dev/null +++ b/packages/api/src/jobs/send_email.ts @@ -0,0 +1,26 @@ +import { env } from '../env' +import { sendWithMailJet } from '../services/send_emails' +import { sendEmail } from '../utils/sendEmail' + +export const SEND_CONFIRMATION_EMAIL_JOB = 'send-confirmation-email' + +export interface SendConfirmationEmailData { + emailAddress: string + link: string + templateData: Record +} + +export const sendConfirmationEmail = async ( + data: SendConfirmationEmailData +) => { + if (process.env.USE_MAILJET) { + return sendWithMailJet(data.emailAddress, data.link) + } + + return sendEmail({ + from: env.sender.message, + to: data.emailAddress, + templateId: env.sendgrid.confirmationTemplateId, + dynamicTemplateData: data.templateData, + }) +} diff --git a/packages/api/src/queue-processor.ts b/packages/api/src/queue-processor.ts index 32b32af47..31bca2588 100644 --- a/packages/api/src/queue-processor.ts +++ b/packages/api/src/queue-processor.ts @@ -36,6 +36,10 @@ import { import { refreshAllFeeds } from './jobs/rss/refreshAllFeeds' import { refreshFeed } from './jobs/rss/refreshFeed' import { savePageJob } from './jobs/save_page' +import { + sendConfirmationEmail, + SEND_CONFIRMATION_EMAIL_JOB, +} from './jobs/send_email' import { syncReadPositionsJob, SYNC_READ_POSITIONS_JOB_NAME, @@ -157,6 +161,8 @@ export const createWorker = (connection: ConnectionOptions) => return processYouTubeTranscript(job.data) case EXPORT_ALL_ITEMS_JOB_NAME: return exportAllItems(job.data) + case SEND_CONFIRMATION_EMAIL_JOB: + return sendConfirmationEmail(job.data) default: logger.warning(`[queue-processor] unhandled job: ${job.name}`) } diff --git a/packages/api/src/services/create_user.ts b/packages/api/src/services/create_user.ts index 062dcccad..d6302ae88 100644 --- a/packages/api/src/services/create_user.ts +++ b/packages/api/src/services/create_user.ts @@ -142,9 +142,7 @@ export const createUser = async (input: { }) if (input.pendingConfirmation) { - if (!(await sendConfirmationEmail(user))) { - return Promise.reject({ errorCode: SignupErrorCode.InvalidEmail }) - } + await sendConfirmationEmail(user) } return [user, profile] diff --git a/packages/api/src/services/send_emails.ts b/packages/api/src/services/send_emails.ts index 886d22a96..a95b4a0cb 100644 --- a/packages/api/src/services/send_emails.ts +++ b/packages/api/src/services/send_emails.ts @@ -1,14 +1,15 @@ +import mailjet from 'node-mailjet' import { env } from '../env' import { generateVerificationToken } from '../utils/auth' +import { enqueueSendConfirmationEmail } from '../utils/createTask' import { logger } from '../utils/logger' import { sendEmail } from '../utils/sendEmail' -import mailjet from 'node-mailjet' export const sendConfirmationEmail = async (user: { id: string name: string email: string -}): Promise => { +}) => { // generate confirmation link const token = generateVerificationToken({ id: user.id }) const link = `${env.client.url}/auth/confirm-email/${token}` @@ -18,19 +19,14 @@ export const sendConfirmationEmail = async (user: { link, } - if (process.env.USE_MAILJET) { - return sendWithMailJet(user.email, link) - } - - return sendEmail({ - from: env.sender.message, - to: user.email, - templateId: env.sendgrid.confirmationTemplateId, - dynamicTemplateData, + await enqueueSendConfirmationEmail({ + emailAddress: user.email, + link, + templateData: dynamicTemplateData, }) } -const sendWithMailJet = async ( +export const sendWithMailJet = async ( email: string, link: string ): Promise => { diff --git a/packages/api/src/utils/createTask.ts b/packages/api/src/utils/createTask.ts index b69b8e8d3..8b6bb3514 100644 --- a/packages/api/src/utils/createTask.ts +++ b/packages/api/src/utils/createTask.ts @@ -35,6 +35,10 @@ import { REFRESH_ALL_FEEDS_JOB_NAME, REFRESH_FEED_JOB_NAME, } from '../jobs/rss/refreshAllFeeds' +import { + SendConfirmationEmailData, + SEND_CONFIRMATION_EMAIL_JOB, +} from '../jobs/send_email' import { SYNC_READ_POSITIONS_JOB_NAME } from '../jobs/sync_read_positions' import { TriggerRuleJobData, TRIGGER_RULE_JOB_NAME } from '../jobs/trigger_rule' import { @@ -69,6 +73,7 @@ export const getJobPriority = (jobName: string): number => { case UPDATE_LABELS_JOB: case UPDATE_HIGHLIGHT_JOB: case SYNC_READ_POSITIONS_JOB_NAME: + case SEND_CONFIRMATION_EMAIL_JOB: return 1 case TRIGGER_RULE_JOB_NAME: case CALL_WEBHOOK_JOB_NAME: @@ -839,4 +844,21 @@ export const enqueueExportItem = async (jobData: ExportItemJobData) => { }) } +export const enqueueSendConfirmationEmail = async ( + jobData: SendConfirmationEmailData +) => { + const queue = await getBackendQueue() + if (!queue) { + return undefined + } + + return queue.add(SEND_CONFIRMATION_EMAIL_JOB, jobData, { + attempts: 1, // only try once + priority: getJobPriority(SEND_CONFIRMATION_EMAIL_JOB), + jobId: `${SEND_CONFIRMATION_EMAIL_JOB}_${jobData.emailAddress}_${JOB_VERSION}`, // deduplication + removeOnComplete: true, + removeOnFail: true, + }) +} + export default createHttpTaskWithToken