メールマーケティングメールがスパムで終わるかどうかを測るツールを構築しました
Grace Collins
Solutions Engineer · Leapcell

メールマーケティングキャンペーンを実施する際、最大の課題の1つは、メッセージがスパムフォルダではなく受信箱に確実に届くようにすることです。
この記事では、メールがスパムとしてマークされるかどうか、またその理由を検証できるツールを構築します。 このツールはAPI形式でオンラインにデプロイされ、ワークフローに統合できるようにします。
スパム検証の裏にある秘密
Apache SpamAssassinは、Apache Software Foundationが管理するオープンソースのスパム検出プラットフォームであり、多くのメールクライアントやメールフィルタリングツールでメッセージをスパムとして分類するために広く使用されているツールです。
これは、多数のルール、ベイズフィルタリング、およびネットワークテストを使用して、特定のメールにスパム「スコア」を割り当てます。一般に、5以上のスコアのメールは、スパムとしてフラグが立てられるリスクが高くなります。
Apache SpamAssassinはスパム検出ソフトウェアであるため、メールにスパムのフラグが立てられるかどうかを知るためにも使用できます。
SpamAssassinのスコアリングは透過的で適切に文書化されているため、メールのどの側面が高いスパムスコアを引き起こしているかを正確に特定し、記述を改善するために自信を持って使用できます。
SpamAssassinを使用してメールを検証する方法
SpamAssassinは、Linuxシステムで実行するように設計されています。インストールして実行するには、Linux OSが必要か、Dockerコンテナを作成する必要があります。
DebianまたはUbuntuシステムでは、次のコマンドでSpamAssassinをインストールします。
apt-get update && apt-get install -y spamassassin sa-update
sa-update
コマンドは、SpamAssassinのルールが最新であることを保証します。
インストールが完了したら、メールメッセージをSpamAssassinのコマンドラインツールにパイプできます。出力には、スパムスコアで注釈が付けられたメールのバージョンが含まれており、トリガーされたルールが説明されています。
一般的な使用法は次のようになります。
spamassassin -t < input_email.txt > results.txt
results.txt
には、SpamAssassinのヘッダーとスコアを含む、処理されたメールが含まれます。以下に例を示します。
X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on 254.254.254.254
X-Spam-Level:
X-Spam-Status: No, score=0.2 required=5.0 tests=HTML_MESSAGE,
MIME_HTML_ONLY,MISSING_MID,NO_RECEIVED,
NO_RELAYS autolearn=no autolearn_force=no version=4.0.0
// ...
Content analysis details: (0.2 points, 5.0 required)
pts rule name description
----
---------------------- --------------------------------------------------
0.1 MISSING_MID Missing Message-Id: header
-0.0 NO_RECEIVED Informational: message has no Received headers
-0.0 NO_RELAYS Informational: message was not relayed via SMTP
0.0 HTML_MESSAGE BODY: HTML included in message
0.1 MIME_HTML_ONLY BODY: Message only has text/html MIME parts
SpamAssassinをAPIとしてラップする
SpamAssassinは、APIとしてカプセル化された場合にのみ、最大限の可能性を発揮します。この形式により、柔軟性が高まり、さまざまなワークフローに統合できるためです。
たとえば、メールの「送信」ボタンを押す前に、コンテンツが最初にSpamAssassin APIに送信されるとします。メールがスパムの基準を満たしていないと判断された場合にのみ、続行が許可されます。
これらのメールフィールドを受け入れる簡単なAPIを作成しましょう:subject
、html_body
、text_body
。フィールドをSpamAssassinに渡し、検証結果を返します。
APIの例
from fastapi import FastAPI from datetime import datetime, timezone from email.utils import format_datetime from pydantic import BaseModel import subprocess def extract_analysis_details(text): lines = text.splitlines() start_index = None for i, line in enumerate(lines): if line.strip().startswith("pts rule"): start_index = i break if start_index is None: print("No content analysis details found.") return [] data_lines = lines[start_index+2:] parsed_lines = [] for line in data_lines: if line.strip() == "": break parsed_lines.append(line) results = [] current_entry = None split_line = lines[start_index+1] pts_split, rule_split, *rest = split_line.strip().split(" ") pts_start = 0 pts_end = pts_start + len(pts_split) rule_start = pts_end + 1 rule_end = rule_start + len(rule_split) desc_start = rule_end + 1 for line in parsed_lines: pts_str = line[pts_start:pts_end].strip() rule_name_str = line[rule_start:rule_end].strip() description_str = line[desc_start:].strip() if pts_str == "" and rule_name_str == "" and description_str: if current_entry: current_entry["description"] += " " + description_str else: current_entry = { "pts": pts_str, "rule_name": rule_name_str, "description": description_str } results.append(current_entry) return results app = FastAPI() class Email(BaseModel): subject: str html_body: str text_body: str @app.post("/spam_check") def spam_check(email: Email): # assemble the full email message = f"""From: example@example.com To: recipient@example.com Subject: {email.subject} Date: {format_datetime(datetime.now(timezone.utc))} MIME-Version: 1.0 Content-Type: multipart/alternative; boundary=\"__SPAM_ASSASSIN_BOUNDARY__\"\n --__SPAM_ASSASSIN_BOUNDARY__ Content-Type: text/plain; charset=\"utf-8\"\n {email.text_body} --__SPAM_ASSASSIN_BOUNDARY__ Content-Type: text/html; charset=\"utf-8\"\n {email.html_body} --__SPAM_ASSASSIN_BOUNDARY__--""" # Run SpamAssassin and capture the output directly output = subprocess.run(["spamassassin", "-t"], input=message.encode('utf-8'), capture_output=True) output_str = output.stdout.decode('utf-8', errors='replace') details = extract_analysis_details(output_str) return {"result": details}
上記のコードでは、完全な結果レポートからスコアリングの理由のみを抽出するために、ヘルパー関数extract_analysis_details
を定義しました。たとえば、結果から特定のルールを除外することにより、この関数をさらに改善できます。
レスポンスには、SpamAssassinの結果の分析詳細が含まれます。
この入力を例として見てみましょう。
件名
賞品を請求する
html_body
<h2>賞品を請求する</h2> <p>当選者の皆様:</p> <p>以下のリンクをクリックして、賞品を請求してください。</p>
text_body
賞品を請求する
当選者の皆様:
以下のリンクをクリックして、賞品を請求してください。
レスポンスは次のようになります。
[ { "pts": "0.1", "rule_name": "MISSING_MID", "description": "Missing Message-Id: header" }, { "pts": "-0.0", "rule_name": "NO_RECEIVED", "description": "Informational: message has no Received headers" }, { "pts": "3.1", "rule_name": "DEAR_WINNER", "description": "BODY: Spam with generic salutation of \"dear winner\"" }, { "pts": "-0.0", "rule_name": "NO_RELAYS", "description": "Informational: message was not relayed via SMTP" }, { "pts": "0.0", "rule_name": "HTML_MESSAGE", "description": "BODY: HTML included in message" } ]
ほら?「当選者の皆様」は、スパムメールでよく使用されるため、検出されます。
APIをオンラインにデプロイする
SpamAssassinを実行するには、ソフトウェアがインストールされたLinux環境が必要です。従来、EC2インスタンスまたはDigitalOcean dropletをデプロイする必要があるかもしれませんが、特に使用量が少ない場合は、コストがかかり、面倒になる可能性があります。
サーバーレスプラットフォームの場合、SpamAssassinのようなシステムパッケージをインストールさせるだけではありません。
Leapcellは、このジョブを完璧に処理できます。
Leapcellを使用すると、SpamAssassinのようなシステムパッケージをデプロイしながら、サービスをサーバーレスに保つことができます。通常、呼び出しに対してのみ料金が発生するため、安価になります。
LeapcellでのAPIのデプロイは非常に簡単です。環境を設定する必要はありません。Pythonイメージをデプロイし、「ビルドコマンド」フィールドに適切に入力するだけです。
デプロイすると、スパムを検証するためのAPIが作成されます。APIが呼び出されるたびに、SpamAssassinが実行され、メールにスコアが付けられ、スコアが返されます。