Forward subscription confirmation email

This commit is contained in:
Hongbo Wu 2023-04-14 18:40:38 +08:00
parent ce4e078754
commit f7d46752e1
2 changed files with 32 additions and 15 deletions

View file

@ -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,

View file

@ -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 = /<mailto:([^>]*)>/
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)
}