2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

スパムフィルタリングの仕組みを理解するための小さなツール

Posted at

Cover

メールを送信する際に最も重要なことは何でしょうか?送信者と受信者ですが、それ以外には?

それ以上に、最も重要な要素は間違いなくスパムフィルタリングです。すべてのメールクライアントにはこの機能が統合されており、その判断がメールの運命を左右します。つまり、あなたがそれを見るかどうかです。

この記事では、スパムフィルタリングの仕組みの原則を説明し、スパムを検出するための小さなツールを構築する方法をガイドします。

あるいは、このツールを使用して、自分のメールがスパムとしてフラグ付けされないように、事前にチェックおよび修正することもできます ;-)。

スパムフィルタリングの仕組み

スパムフィルタリングは、しばしばApache SpamAssassinと呼ばれるプログラムに依存します。

Apache SpamAssassinはApache Software Foundationによって維持されているオープンソースのスパム検出プラットフォームであり、多くのメールクライアントやメールフィルタリングツールがメッセージをスパムとして分類するために使用する広く普及したツールです。

数多くのルール、ベイジアンフィルタリング、ネットワークテストを使用して、指定されたメールにスパム「スコア」を割り当てます。一般的に、スコアが5以上のメールはスパムとしてフラグ付けされるリスクが高いです。

スパム検出のためにSpamAssassinをローカルにインストールする

SpamAssassinはLinuxでのみ実行できることに注意してください。LinuxオペレーティングシステムまたはDockerコンテナが必要です。

Debian/Ubuntuシステムでは、SpamAssassinをインストールするために次のコマンドを使用します。

apt-get update && apt-get install -y spamassassin
sa-update

sa-updateコマンドは、SpamAssassinの検出ルールを最新バージョンに更新するために使用されます。

インストールしたら、それを使用してスパムを検出できます。使い方は次のとおりです。

spamassassin -t < input_email.txt > results.txt

このコマンドはinput_email.txtをSpamAssassinに渡し、検出結果を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でラップする

Linux以外のデバイスがSpamAssassinを使用できるようにしたり、他のワークフローに統合したりするために、APIでラップできます。

たとえば、このAPIの典型的なユースケースは次のようになります。メールの「送信」ボタンをクリックする前に、コンテンツが最初にSpamAssassin APIに送信されます。メールは、スパムではない基準を満たしている場合にのみ送信が許可されます。

次に、Pythonを使用して、subjecthtml_bodytext_bodyという以下のメールフィールドを受け入れる簡単なAPIを作成します。これらのフィールドをSpamAssassinに渡し、検証結果を返します。

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__"

--__SPAM_ASSASSIN_BOUNDARY__
Content-Type: text/plain; charset="utf-8"

{email.text_body}

--__SPAM_ASSASSIN_BOUNDARY__
Content-Type: text/html; charset="utf-8"

{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を定義しています。たとえば、結果から特定のルールをフィルタリングするなど、この関数をさらに変更できます。

このAPIをテストしてみましょう。次のパラメータを渡します。

subject

Claim Your Prize

html_body

<h2>Claim Your Prize</h2>
<p>Dear Winner:</p>
<p>Click the link below to claim your prize.</p>

text_body

Claim Your Prize

Dear Winner:
Click the link below to claim your prize.

返される結果は次のとおりです。

[
  {
    "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"
  }
]

ご覧のとおり、「Dear winner」というフレーズは、さまざまなスパムメールで頻繁に使用されるため、非常に疑わしいです。

このAPIツールをオンラインでデプロイする

この小さなツールをオンラインでデプロイすることで、いつでもスパムを検出できます。

このツールはPythonで記述されており、事前にApache SpamAssassinをインストールする必要があるため、AWS EC2やDigitalOceanのようなサービスのみを使用してデプロイできると思われるかもしれません。しかし、これらは高価になる可能性があり、デプロイプロセスは複雑です。

より適切なツールはありますか?

はい、Leapcellを使用してデプロイできます。

Leapcell

Leapcellは、Python、Go、Rustを含むさまざまな言語のデプロイをサポートしています。Dockerアーキテクチャを使用しており、さまざまな基盤ライブラリのインストールを可能にします。最も重要なのは、Leapcellは実際のAPI呼び出し回数に基づいてのみ課金するため、アイドル状態のプロジェクトを保持するのは完全に無料です。これにより、AWSやDigitalOceanのようなプラットフォームよりも大幅に安価になります。

デプロイ手順は簡単です。

  1. プロジェクトをGitHubにプッシュします。

  2. Leapcellで「Create Service」をクリックし、このGitHubプロジェクトを選択します。

  3. 「Build Command」フィールドに次のコマンドを入力してSpamAssassinをインストールします。

apt-get update && apt-get install -y spamassassin
sa-update
pip install -r requirements.txt

Example

  1. 「Submit」をクリックします。

デプロイすると、スパム検証のためのAPIが利用可能になります!APIが呼び出されるたびに、SpamAssassinが実行され、メールがスコアリングされ、スコアが返されます。


Xでフォローする:@LeapcellJP


ブログでこの記事を読む

関連記事:

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?