Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

スパムフィルタリング

キーワード分析、ドメインレピュテーション、機械学習を使い、高度なスパム検出を実装します

最終更新 Markdown で表示Agent セットアップ

キーワード照合、ドメイン検証、高度な検出手法で、メールセキュリティ向けのスパムフィルタリングを構築します。

基本的なスパムフィルター

キーワード照合とドメイン検証による、単純なスパム検出です。

interface Env {
	EMAIL: SendEmail;
	EMAIL_ANALYTICS: AnalyticsEngine;
}

interface SpamFilter {
	checkSpam(
		message: any,
	): Promise<{ isSpam: boolean; score: number; reasons: string[] }>;
}

class SimpleSpamFilter implements SpamFilter {
	private spamKeywords = [
		"buy now",
		"limited time",
		"act fast",
		"click here",
		"free money",
		"guaranteed",
		"risk free",
		"urgent",
		"winner",
		"congratulations",
		"inheritance",
		"lottery",
	];

	private trustedDomains = ["example.com", "trusted-partner.com", "vendor.net"];

	async checkSpam(
		message,
	): Promise<{ isSpam: boolean; score: number; reasons: string[] }> {
		let score = 0;
		const reasons = [];

		const sender = message.from;
		const subject = message.headers.get("subject") || "";
		const senderDomain = sender.split("@")[1];

		// Check sender domain
		if (this.trustedDomains.includes(senderDomain)) {
			score -= 2; // Trusted sender
		}

		// Check subject for spam keywords
		const subjectLower = subject.toLowerCase();
		for (const keyword of this.spamKeywords) {
			if (subjectLower.includes(keyword)) {
				score += 1;
				reasons.push(`Spam keyword: ${keyword}`);
			}
		}

		// Check for excessive capitalization
		const capsRatio = (subject.match(/[A-Z]/g) || []).length / subject.length;
		if (capsRatio > 0.7 && subject.length > 10) {
			score += 1;
			reasons.push("Excessive capitalization");
		}

		// Check for suspicious patterns
		if (subject.includes("!!!") || subject.includes("$$$")) {
			score += 1;
			reasons.push("Suspicious punctuation");
		}

		// Check for suspicious sender patterns
		if (
			sender.includes("noreply") &&
			subject.toLowerCase().includes("urgent")
		) {
			score += 2;
			reasons.push("Suspicious noreply + urgent combination");
		}

		return {
			isSpam: score >= 2,
			score,
			reasons,
		};
	}
}

const spamFilter = new SimpleSpamFilter();

export default {
	async email(message, env, ctx): Promise<void> {
		const startTime = Date.now();

		// Check for spam
		const spamCheck = await spamFilter.checkSpam(message);

		// Track spam check metrics
		env.EMAIL_ANALYTICS?.writeDataPoint({
			blobs: [
				"spam_check_completed",
				message.from,
				message.to,
				spamCheck.isSpam ? "spam" : "legitimate",
			],
			doubles: [
				1, // Count
				spamCheck.score,
				Date.now() - startTime,
			],
			indexes: [
				`spam_detected:${spamCheck.isSpam}`,
				`score_range:${getScoreRange(spamCheck.score)}`,
			],
		});

		if (spamCheck.isSpam) {
			console.log(
				`Rejected spam email from ${message.from}: ${spamCheck.reasons.join(", ")}`,
			);
			message.setReject(`Message rejected: ${spamCheck.reasons[0]}`);
			return;
		}

		// Add spam score headers and forward
		const headers = new Headers();
		headers.set("X-Spam-Score", spamCheck.score.toString());
		headers.set("X-Spam-Reasons", spamCheck.reasons.join(", "));
		headers.set("X-Spam-Check-Time", (Date.now() - startTime).toString());

		await message.forward("[email protected]", headers);
	},
};

function getScoreRange(score: number): string {
	if (score < 0) return "trusted";
	if (score === 0) return "neutral";
	if (score === 1) return "suspicious";
	return "spam";
}

AI を使った高度なスパム検出

より高度なスパム検出では、Workers AI で基本フィルターを拡張し、機械学習モデルでメール本文を分析できます。キーワードベースのフィルターでは見逃しやすい、微妙なスパムパターンも検出できます。

次のステップ

役に立ちましたか?