feat: add ENABLE_CHECK_JUNK_MAIL (#469)

This commit is contained in:
Dream Hunter
2024-11-07 00:58:15 +08:00
committed by GitHub
parent 49b3f10838
commit ddfa2c5d03
9 changed files with 72 additions and 2 deletions
+1
View File
@@ -5,6 +5,7 @@
- feat: 支持提前设置 bot info, 降低 telegram 回调延迟 (#441) - feat: 支持提前设置 bot info, 降低 telegram 回调延迟 (#441)
- feat: 增加 telegram mini app 的 build 压缩包 - feat: 增加 telegram mini app 的 build 压缩包
- feat: 增加是否启用垃圾邮件检查 `ENABLE_CHECK_JUNK_MAIL` 配置
## v0.7.5 ## v0.7.5
+2
View File
@@ -130,6 +130,8 @@ ENABLE_AUTO_REPLY = false
# FORWARD_ADDRESS_LIST = ["xxx@xxx.com"] # FORWARD_ADDRESS_LIST = ["xxx@xxx.com"]
# Frontend URL # Frontend URL
# FRONTEND_URL = "https://xxxx.xxx" # FRONTEND_URL = "https://xxxx.xxx"
# Enable check junk mail
# ENABLE_CHECK_JUNK_MAIL = false
[[d1_databases]] [[d1_databases]]
binding = "DB" binding = "DB"
@@ -103,6 +103,8 @@ ENABLE_AUTO_REPLY = false
# FORWARD_ADDRESS_LIST = ["xxx@xxx.com"] # FORWARD_ADDRESS_LIST = ["xxx@xxx.com"]
# 前端地址,用于发送 webhook 的邮件 url # 前端地址,用于发送 webhook 的邮件 url
# FRONTEND_URL = "https://xxxx.xxx" # FRONTEND_URL = "https://xxxx.xxx"
# 是否启用垃圾邮件检查
# ENABLE_CHECK_JUNK_MAIL = false
# D1 数据库的名称和 ID 可以在 cloudflare 控制台查看 # D1 数据库的名称和 ID 可以在 cloudflare 控制台查看
[[d1_databases]] [[d1_databases]]
+2 -1
View File
@@ -40,7 +40,8 @@ export default {
"S3_ENABLED": isS3Enabled(c), "S3_ENABLED": isS3Enabled(c),
"VERSION": CONSTANTS.VERSION, "VERSION": CONSTANTS.VERSION,
"DISABLE_SHOW_GITHUB": !getBooleanValue(c.env.DISABLE_SHOW_GITHUB), "DISABLE_SHOW_GITHUB": !getBooleanValue(c.env.DISABLE_SHOW_GITHUB),
"DISABLE_ADMIN_PASSWORD_CHECK": getBooleanValue(c.env.DISABLE_ADMIN_PASSWORD_CHECK) "DISABLE_ADMIN_PASSWORD_CHECK": getBooleanValue(c.env.DISABLE_ADMIN_PASSWORD_CHECK),
"ENABLE_CHECK_JUNK_MAIL": getBooleanValue(c.env.ENABLE_CHECK_JUNK_MAIL),
}) })
} }
} }
+3 -1
View File
@@ -260,7 +260,8 @@ export const commonParseMail = async (raw_mail: string | undefined | null): Prom
sender: string, sender: string,
subject: string, subject: string,
text: string, text: string,
html: string html: string,
headers?: Record<string, string>[]
} | undefined> => { } | undefined> => {
if (!raw_mail) { if (!raw_mail) {
return undefined; return undefined;
@@ -287,6 +288,7 @@ export const commonParseMail = async (raw_mail: string | undefined | null): Prom
subject: parsedEmail.subject || "", subject: parsedEmail.subject || "",
text: parsedEmail.text || "", text: parsedEmail.text || "",
html: parsedEmail.html || "", html: parsedEmail.html || "",
headers: parsedEmail.headers || [],
}; };
} }
catch (e) { catch (e) {
+44
View File
@@ -0,0 +1,44 @@
import { Bindings } from "../types";
import { getBooleanValue } from "../utils";
import { commonParseMail } from "../common";
export const check_if_junk_mail = async (
env: Bindings, address: string,
raw_mail: string, message_id: string | null
): Promise<boolean> => {
if (!getBooleanValue(env.ENABLE_CHECK_JUNK_MAIL)) {
return false;
}
const parsedEmail = await commonParseMail(raw_mail);
if (!parsedEmail?.headers) return false;
const headers = parsedEmail.headers;
for (const header of headers) {
if (!header["key"]) continue;
if (!header["value"]) continue;
// check spf
if (header["key"].toLowerCase() == "received-spf"
&&
!header["value"].toLowerCase().includes("pass")
) {
return true;
}
// check dkim and dmarc
if (header["key"].toLowerCase() == "authentication-results") {
if (header["value"].toLowerCase().includes("dkim=")
&&
!header["value"].toLowerCase().includes("dkim=pass")
) {
return true;
}
if (header["value"].toLowerCase().includes("dmarc=")
&&
!header["value"].toLowerCase().includes("dmarc=pass")
) {
return true;
}
}
}
return false;
}
+14
View File
@@ -6,6 +6,7 @@ import { Bindings, HonoCustomType } from "../types";
import { auto_reply } from "./auto_reply"; import { auto_reply } from "./auto_reply";
import { isBlocked } from "./black_list"; import { isBlocked } from "./black_list";
import { triggerWebhook } from "../common"; import { triggerWebhook } from "../common";
import { check_if_junk_mail } from "./check_junk";
async function email(message: ForwardableEmailMessage, env: Bindings, ctx: ExecutionContext) { async function email(message: ForwardableEmailMessage, env: Bindings, ctx: ExecutionContext) {
@@ -15,6 +16,19 @@ async function email(message: ForwardableEmailMessage, env: Bindings, ctx: Execu
return; return;
} }
const rawEmail = await new Response(message.raw).text(); const rawEmail = await new Response(message.raw).text();
// check if junk mail
try {
const is_junk = await check_if_junk_mail(env, message.to, rawEmail, message.headers.get("Message-ID"));
if (is_junk) {
message.setReject("Junk mail");
console.log(`Junk mail from ${message.from} to ${message.to}`);
return;
}
} catch (error) {
console.log("check junk mail error", error);
}
const message_id = message.headers.get("Message-ID"); const message_id = message.headers.get("Message-ID");
// save email // save email
const { success } = await env.DB.prepare( const { success } = await env.DB.prepare(
+2
View File
@@ -42,6 +42,8 @@ export type Bindings = {
DISABLE_SHOW_GITHUB: string | boolean | undefined DISABLE_SHOW_GITHUB: string | boolean | undefined
FORWARD_ADDRESS_LIST: string | string[] | undefined FORWARD_ADDRESS_LIST: string | string[] | undefined
ENABLE_CHECK_JUNK_MAIL: string | boolean | undefined
// s3 config // s3 config
S3_ENDPOINT: string | undefined S3_ENDPOINT: string | undefined
S3_ACCESS_KEY_ID: string | undefined S3_ACCESS_KEY_ID: string | undefined
+2
View File
@@ -72,6 +72,8 @@ ENABLE_AUTO_REPLY = false
# FORWARD_ADDRESS_LIST = ["xxx@xxx.com"] # FORWARD_ADDRESS_LIST = ["xxx@xxx.com"]
# Frontend URL # Frontend URL
# FRONTEND_URL = "https://xxxx.xxx" # FRONTEND_URL = "https://xxxx.xxx"
# Enable check junk mail
# ENABLE_CHECK_JUNK_MAIL = false
[[d1_databases]] [[d1_databases]]
binding = "DB" binding = "DB"