Skip to content

Instantly share code, notes, and snippets.

@leyuskckiran1510
Created September 25, 2025 16:07
Show Gist options
  • Select an option

  • Save leyuskckiran1510/d32f6a5b45ef1b18e331e64d2f91fac0 to your computer and use it in GitHub Desktop.

Select an option

Save leyuskckiran1510/d32f6a5b45ef1b18e331e64d2f91fac0 to your computer and use it in GitHub Desktop.
Clodflare email job scanner and discord notifier
const FALLBACK_WEBHOOK = "";
const FALLBACK_EMAIL = ""
export default {
// https://developers.cloudflare.com/email-routing/email-workers/runtime-api/
async email(message, env, ctx) {
let _email = env.EMAIL || FALLBACK_EMAIL;
console.log("Forwarding email to:", _email)
await message.forward(_email);
console.log("Done.")
console.log("Now sending updates on discord ... ")
const webhook = env.WEBHOOK || FALLBACK_WEBHOOK;
console.log("Using webhook:", webhook);
const subject = message.headers.get("subject") || "(no subject)";
const from = message.headers.get("from") || "(unknown sender)";
const raw = await new Response(message.raw).text();
let body = "";
if (raw.includes("Content-Type: multipart")) {
let boundary = raw.split(/Content\-Type:[^"]+"/)[1].split(/"/)[0]
console.log("Boundary is: ", boundary);
let afterBoundry = raw.split(`--${boundary}`)
if (afterBoundry && afterBoundry.length > 1) {
console.log("Found afterBoundry: ")
let raw_texts = afterBoundry[1].split(/Content\-Type[^\n]+[\n]+/)
if (raw_texts && raw_texts.length > 1) {
console.log("Extracted raw text.")
body = raw_texts[1].trim()
} else {
body = afterBoundry[1].trim()
}
} else {
body = raw.trim()
}
} else {
const bodyMatch = raw.match(/\r?\n\r?\n([\s\S]+)$/);
if (bodyMatch) {
body = bodyMatch[1].split(/text\/plain[^\n]+\n+/)[1].split(/--/)[0].trim();
}
}
if (!body) {
const lines = raw.split('\n');
let foundEmptyLine = false;
const bodyLines = [];
for (const line of lines) {
if (!foundEmptyLine && line.trim() === '') {
foundEmptyLine = true;
continue;
}
if (foundEmptyLine && !line.startsWith('--') && line.trim() !== '') {
bodyLines.push(line);
}
}
body = bodyLines.join('\n').trim();
}
const keywords = [
"accepted",
"congratulations",
"selected",
"we are pleased to inform you",
"we are excited to offer",
"you have been chosen",
"we're happy to move forward",
"your application was successful",
];
const content = body.toLowerCase();
const isAccepted = keywords.some((phrase) => content.includes(phrase));
const emoji = isAccepted ? "✅" : "❌";
let bodyChunks = [];
for (let i = 0; i < body.length; i += 1900) {
bodyChunks.push(body.slice(i, i + 1900));
}
const ping = isAccepted ? "<@admin>" : '';
const _color = isAccepted ? 4114738 : 16727871;
const payload = {
username: "Email Worker",
avatar_url: "https://developers.cloudflare.com/favicon.png",
content: ping,
embeds: [{
title: `${subject} ${emoji}`,
description: bodyChunks[0],
color: _color,
author: {
name: from,
},
}]
};
console.log("Sending payload[0] to discord ....");
await fetch(webhook, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload),
});
console.log("Done.");
for (let j = 1; j < bodyChunks.length; j++) {
const payload = {
username: "Email Worker",
avatar_url: "https://developers.cloudflare.com/favicon.png",
embeds: [{
description: bodyChunks[j],
color: _color,
}]
};
console.log("Sending payload[", j, "] to discord ....");
await fetch(webhook, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload),
});
console.log("Done.");
}
},
// https://developers.cloudflare.com/workers/runtime-apis/fetch/
async fetch(request, env, ctx) {
return new Response("Email Worker by - <a href='mailto:me@kiranrajdhakal.com.np'>leyuskc<a>", {
headers: {
"content-type": "text/html",
},
});
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment