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. [email protected]), 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 hidden or 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: | |
| * [email protected] would forward to Alice. | |
| * [email protected] 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 (/\[email protected]\b/gi.test(recipient)) { | |
| await message.forward("[email protected]"); | |
| } else if (/\[email protected]\b/gi.test(recipient)) { | |
| await message.forward("[email protected]"); | |
| } else { | |
| await message.forward("[email protected]"); | |
| } | |
| } | |
| /** | |
| * 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 <[email protected]>; 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 <)[email protected](?=>;)\b/gi)[0]; | |
| } | |
| export default { | |
| } |
Author
message.tois the recipient. If you are not the recipient (because you receive the email as BCC), you cannot filter using this property.
No, this seems not to be the case. message.to is not the the same as the to property from the header. Give it a try, it really simplifies the code and works well. also for cc and bcc cases ;)
Author
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
message.tois the recipient. If you are not the recipient (because you receive the email as BCC), you cannot filter using this property.