From f7d46752e1a31ec706040a0695803010ed9ea768 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 14 Apr 2023 18:40:38 +0800 Subject: [PATCH] Forward subscription confirmation email --- packages/inbound-email-handler/src/index.ts | 17 +++++++---- .../inbound-email-handler/src/newsletter.ts | 30 +++++++++++++------ 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/packages/inbound-email-handler/src/index.ts b/packages/inbound-email-handler/src/index.ts index f14b94f9c..42d86f9eb 100644 --- a/packages/inbound-email-handler/src/index.ts +++ b/packages/inbound-email-handler/src/index.ts @@ -13,8 +13,9 @@ import parseHeaders from 'parse-headers' import * as multipart from 'parse-multipart-data' import { promisify } from 'util' import { - handleConfirmation, - isConfirmationEmail, + handleGoogleConfirmationEmail, + isGoogleConfirmationEmail, + isSubscriptionConfirmationEmail, parseUnsubscribe, } from './newsletter' import { handlePdfAttachment } from './pdf' @@ -132,10 +133,13 @@ export const inboundEmailHandler = Sentry.GCPFunction.wrapHttpFunction( }) try { - // check if it is a confirmation email or forwarding newsletter - if (isConfirmationEmail(from, subject)) { - console.log('handleConfirmation', from) - await handleConfirmation(to, subject) + // check if it is a subscription google confirmation email + const isGoogleConfirmation = isGoogleConfirmationEmail(from, subject) + if (isGoogleConfirmation || isSubscriptionConfirmationEmail(subject)) { + console.debug('handleConfirmation', from, subject) + // we need to parse the confirmation code from the email + isGoogleConfirmation && + (await handleGoogleConfirmationEmail(to, subject)) // queue non-newsletter emails await pubsub.topic(NON_NEWSLETTER_EMAIL_TOPIC).publishMessage({ json: { @@ -163,6 +167,7 @@ export const inboundEmailHandler = Sentry.GCPFunction.wrapHttpFunction( ) return res.send('ok') } + // all other emails are considered newsletters const newsletterMessage = await handleNewsletter({ from, to, diff --git a/packages/inbound-email-handler/src/newsletter.ts b/packages/inbound-email-handler/src/newsletter.ts index b3239f55d..b3686b20e 100644 --- a/packages/inbound-email-handler/src/newsletter.ts +++ b/packages/inbound-email-handler/src/newsletter.ts @@ -7,12 +7,14 @@ interface Unsubscribe { httpUrl?: string } -const EMAIL_CONFIRMATION_CODE_RECEIVED_TOPIC = 'emailConfirmationCodeReceived' -const CONFIRMATION_EMAIL_SENDER_ADDRESS = 'forwarding-noreply@google.com' +const GOOGLE_CONFIRMATION_CODE_RECEIVED_TOPIC = 'emailConfirmationCodeReceived' +const GOOGLE_CONFIRMATION_EMAIL_SENDER_ADDRESS = 'forwarding-noreply@google.com' // check unicode parentheses too -const CONFIRMATION_CODE_PATTERN = /\d+/u +const GOOGLE_CONFIRMATION_CODE_PATTERN = /\d+/u const UNSUBSCRIBE_HTTP_URL_PATTERN = /<(https?:\/\/[^>]*)>/ const UNSUBSCRIBE_MAIL_TO_PATTERN = /]*)>/ +const CONFIRMATION_EMAIL_SUBJECT_PATTERN = + /(confirm|verify).*(newsletter(s)*|subscription(s)*|sign\s*up)/i export const parseUnsubscribe = (unSubHeader: string): Unsubscribe => { // parse list-unsubscribe header @@ -32,7 +34,10 @@ const parseAddress = (address: string): string => { return '' } -export const handleConfirmation = async (email: string, subject: string) => { +export const handleGoogleConfirmationEmail = async ( + email: string, + subject: string +) => { console.log('confirmation email', email, subject) const confirmationCode = getConfirmationCode(subject) @@ -47,11 +52,11 @@ export const handleConfirmation = async (email: string, subject: string) => { } const message = { emailAddress: email, confirmationCode: confirmationCode } - return publishMessage(EMAIL_CONFIRMATION_CODE_RECEIVED_TOPIC, message) + return publishMessage(GOOGLE_CONFIRMATION_CODE_RECEIVED_TOPIC, message) } export const getConfirmationCode = (subject: string): string | undefined => { - const matches = subject.match(CONFIRMATION_CODE_PATTERN) + const matches = subject.match(GOOGLE_CONFIRMATION_CODE_PATTERN) if (matches) { // get the number code only // e.g. (#123456) => 123456 @@ -60,9 +65,16 @@ export const getConfirmationCode = (subject: string): string | undefined => { return undefined } -export const isConfirmationEmail = (from: string, subject: string): boolean => { +export const isGoogleConfirmationEmail = ( + from: string, + subject: string +): boolean => { return ( - parseAddress(from) === CONFIRMATION_EMAIL_SENDER_ADDRESS && - CONFIRMATION_CODE_PATTERN.test(subject) + parseAddress(from) === GOOGLE_CONFIRMATION_EMAIL_SENDER_ADDRESS && + GOOGLE_CONFIRMATION_CODE_PATTERN.test(subject) ) } + +export const isSubscriptionConfirmationEmail = (subject: string): boolean => { + return CONFIRMATION_EMAIL_SUBJECT_PATTERN.test(subject) +}