Last active
March 9, 2025 05:48
-
-
Save landgenoot/07e3d64e3f3db49c5075e5428cbc87eb to your computer and use it in GitHub Desktop.
Cloudflare Email Worker that parses flags in the local-part of the email address (e.g. somerandomtext-a@example.com), even if the receipient is in the BCC. Corresponding blog post: https://daanmiddendorp.com/tech/2023/06/28/parsing-bcc-recipient-with-cloudflare-email-workers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Cloudflare Email Worker that parses flags (e.g. -a) and forwards accordingly. | |
* | |
* Example: | |
* somerandomtext-a@example.com would forward to Alice. | |
* somerandomtext-b@example.com would forward to Bob. | |
*/ | |
async function email(message, env, ctx) { | |
let messageSource = await fetchMessageSource(message.raw); | |
let blacklist = await fetchBlacklist("https://example.com/blacklist.txt"); | |
let recipient = parseRecipient(messageSource); | |
if (blacklist.indexOf(recipient) > -1) { | |
return message.setReject("Address is blocked"); | |
} | |
if (/\b.+-a@example.com\b/gi.test(recipient)) { | |
await message.forward("alice@company.com"); | |
} else if (/\b.+-b@example.com\b/gi.test(recipient)) { | |
await message.forward("bob@company.com"); | |
} else { | |
await message.forward("catchall@company.com"); | |
} | |
} | |
/** | |
* Fetch readable stream, so that we can convert the raw message into a string. | |
* @param ReadableStream message | |
* @return string messageSource | |
*/ | |
async function fetchMessageSource(message) { | |
const rawMessage = new Response(message); | |
const arrayBuffer = await rawMessage.arrayBuffer(); | |
const messageSource = String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)); | |
return messageSource; | |
} | |
/** | |
* Download text file and split on newlines. | |
* @param string url location of the blacklist | |
* @return string[] blacklist | |
*/ | |
async function fetchBlacklist(url) { | |
const response = await fetch(url, {}); | |
const blacklist = (await response.text()).split("\n"); | |
return blacklist; | |
} | |
/** | |
* Parse receipient from Received header (even if BCC'ed) | |
* Example header: | |
* | |
* Received: by mail-vk1-f194.google.com with SMTP id 71fab90a1359d-47167a4ce3cso2249208e0c.2 | |
* for <iets2-d@example.com>; Wed, 28 Jun 2023 04:30:15 -0700 (PDT) | |
* | |
* @param string messageSource | |
* @return string recipient email address | |
*/ | |
function parseRecipient(messageSource) { | |
return messageSource.match(/\b(?<=for <).+@example.com(?=>;)\b/gi)[0]; | |
} | |
export default { | |
} |
You are right. RFC5322.To
vs RFC5321.RcptTo
I am not sure if the API has changed in the meantime (Cloudflare email workers was in beta back then) or I have been ignorant. Probably the latter. Thank you!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
No, this seems not to be the case.
message.to
is not the the same as theto
property from the header. Give it a try, it really simplifies the code and works well. also for cc and bcc cases ;)