Merge pull request #1009 from omnivore-app/fix/unsubscribe

fix not getting unsubscribe email address from beehiv newsletter by decoding the list-unsubscribe header
This commit is contained in:
Hongbo Wu
2022-07-27 09:41:42 +08:00
committed by GitHub
5 changed files with 45 additions and 19 deletions

View File

@ -23,6 +23,7 @@
"@types/addressparser": "^1.0.1",
"@types/json-bigint": "^1.0.1",
"@types/node": "^14.11.2",
"@types/rfc2047": "^2.0.1",
"eslint-plugin-prettier": "^4.0.0"
},
"dependencies": {
@ -34,6 +35,7 @@
"axios": "^0.27.2",
"jsonwebtoken": "^8.5.1",
"parse-headers": "^2.0.4",
"parse-multipart-data": "^1.2.1"
"parse-multipart-data": "^1.2.1",
"rfc2047": "^4.0.1"
}
}

View File

@ -65,29 +65,24 @@ export const inboundEmailHandler = Sentry.GCPFunction.wrapHttpFunction(
console.log('headers: ', headers)
try {
const from = parsed.from.toString()
const from = parsed.from
const subject = parsed.subject
const html = parsed.html
const text = parsed.text
const forwardedAddress = headers['x-forwarded-to']
const recipientAddress = forwardedAddress
? forwardedAddress.toString()
: parsed.to
const postHeader = headers['list-post']
? headers['list-post'].toString()
: ''
const unSubHeader = headers['list-unsubscribe']
? headers['list-unsubscribe'].toString()
: ''
const recipientAddress = forwardedAddress?.toString() || parsed.to
const postHeader = headers['list-post']?.toString()
const unSubHeader = headers['list-unsubscribe'].toString()
// check if it is a forwarding confirmation email or newsletter
const newsletterHandler = getNewsletterHandler(
postHeader,
from,
unSubHeader
)
try {
// check if it is a forwarding confirmation email or newsletter
const newsletterHandler = getNewsletterHandler(
postHeader,
from,
unSubHeader
)
if (newsletterHandler) {
console.log('handleNewsletter', from, recipientAddress)
await newsletterHandler.handleNewsletter(

View File

@ -1,6 +1,7 @@
import { PubSub } from '@google-cloud/pubsub'
import { v4 as uuidv4 } from 'uuid'
import addressparser from 'addressparser'
import rfc2047 from 'rfc2047'
interface Unsubscribe {
mailTo?: string
@ -20,9 +21,10 @@ const UNSUBSCRIBE_MAIL_TO_PATTERN = /<mailto:([^>]*)>/
export const parseUnsubscribe = (unSubHeader: string): Unsubscribe => {
// parse list-unsubscribe header
// e.g. List-Unsubscribe: <https://omnivore.com/unsub>, <mailto:unsub@omnivore.com>
const decoded = rfc2047.decode(unSubHeader)
return {
mailTo: unSubHeader.match(UNSUBSCRIBE_MAIL_TO_PATTERN)?.[1],
httpUrl: unSubHeader.match(UNSUBSCRIBE_HTTP_URL_PATTERN)?.[1],
mailTo: decoded.match(UNSUBSCRIBE_MAIL_TO_PATTERN)?.[1],
httpUrl: decoded.match(UNSUBSCRIBE_HTTP_URL_PATTERN)?.[1],
}
}

View File

@ -167,5 +167,15 @@ describe('Newsletter email test', () => {
expect(parseUnsubscribe(header).httpUrl).to.equal(httpUrl)
})
context('when unsubscribe header rfc2047 encoded', () => {
it('returns mail to address if exists', () => {
const header = `=?us-ascii?Q?=3Cmailto=3A654e9594-184c-4884-8e02-e6e58a3a6871+87e39b3d-c3ca-4be?= =?us-ascii?Q?b-ba4d-977cc2ba61e7+067a353f-f775-4f2c-?= =?us-ascii?Q?a5cc-978df38deeca=40unsub=2Ebeehiiv=2Ecom=3E=2C?= =?us-ascii?Q?_=3Chttps=3A=2F=2Fwww=2Emilkroad=2Ecom=2Fsubscribe=2F87e39b3d-c3ca-4beb-ba4d-97?= =?us-ascii?Q?7cc2ba61e7=2Fmanage=3Fpost=5Fid=3D067a353f-f775?= =?us-ascii?Q?-4f2c-a5cc-978df38deeca=3E?=',`
expect(parseUnsubscribe(header).mailTo).to.equal(
'654e9594-184c-4884-8e02-e6e58a3a6871+87e39b3d-c3ca-4beb-ba4d-977cc2ba61e7+067a353f-f775-4f2c-a5cc-978df38deeca@unsub.beehiiv.com'
)
})
})
})
})