迷惑メールが増えているとのこと。前からな気もしますが、ドメインが明らかに偽装されたメールがフィルタをすり抜けてきます。*1
cf. 迷惑メールが爆増中。Yahoo!メールでも対策へ | マイナビニュース
それならというわけでMac上で動くローカルLLMに判別させてみることにしました。*2。人間なら送信元(ドメイン)と件名を見れば判別可能なので、高速化・複雑化抑止のため、入力はこれだけとします。
モデルは Gemma-4-E4B を使用しました。(最初 1-bit Bonsai を試しましたが日本に関する知識が乏しすぎてプロンプトの工夫レベルではどうにもならなさそうでした。)
実行には llama.cpp を利用。セットアップは以下の手順に従うだけです。
unsloth.ai
以下コマンドでサーバーを起動しておきます。高速化のため reasoning はオフにして代わりにプロンプトで根拠を述べさせています(現在の説明によると --chat-template-kwargs '{"enable_thinking":false}' とすべきかもです)。後で述べますが複数回実行させており、その際に観点が少し変わることがあるので temperature は少し高めを指定しました。
export LLAMA_CACHE="unsloth/gemma-4-E4B-it-GGUF" ./build/bin/llama-server -hf unsloth/gemma-4-E4B-it-GGUF:Q8_0 --temp 0.5 --top-p 0.95 --top-k 64 --reasoning off &
evaluate_mail_sender.sh として、送信元とタイトルを引数に渡すと OK/BAD のどちらかを結果として返すコマンドを用意します。自信がないのか回答がブレることもあるため、最大3回実行して多数決を取っています。判断の根拠はログファイルに記録されます。
#!/bin/zsh set -e prompt='次のメールで、FROM の名称("名前 <...@...>"の"名前"部分)もしくはSubjectに含まれる送信元名称と、FROMのドメインを比較して、全く関係ない送信元を偽装したメールかを判定して。特にFROMに記述された名称とドメインの不一致は問題のある可能性が高い。Subjectは「【送信元】〜」のように名称であることを強調している場合には重視する。名称かが曖昧な場合や、確実でない場合は偽装だと判断してはならない。根拠を述べた後、最後の行に、送信元偽装の可能性が高い場合には「BAD」と、問題ない場合・不確かな場合は「OK」とプレインテキストで出力して。' target="From: $from / Subject: \"$subj\"" bad=0 ok=0 for i in {{1..3}}; do result=$(curl -fs http://127.0.0.1:8080/v1/chat/completions -H "Content-Type: application/json" -d '{"messages":[{"role":"system","content":"'"${prompt//\"/\\\"}"'"},{"role":"user","content":"'"${target//\"/\\\"}"'"}],"temperature":0.5}' | jq -r '.choices[].message.content') result_str=$(tail -1 <<<"$result") echo "$target\n$result\n" >>/tmp/llm-result.log grep -q BAD <<<"$result_str" && bad=$(($bad+1)) if [[ "$bad" -eq 2 ]]; then echo BAD exit fi grep -q OK <<<"$result_str" && ok=$(($ok+1)) if [[ "$ok" -eq 2 ]]; then echo OK exit fi done
あとはこれを使ってメールのフィルタリングをする設定をします。なお、メールアプリとしては Mac の Mail.app で動作させることにします。
まずはスクリプトエディタで次の AppleScript を作成し、 ~/Library/Application\ Scripts/com.apple.mail/ に eval-with-llm.scpt として保存します(形式はスクリプト)。
これは受信メールに対してルール評価時に先ほどのコマンドを使って結果が BAD なら迷惑メールに移動させるものです。
以前の Mail.app ではもっと簡単に動いていたんですが、どこかのバージョンから Mail.app の AppleScript フィルタ機能がバグってしまっているらしく、perform mail action に正しい受信メールが渡ってきません。。。仕方がないので、適当に少し待ってから自分自身を run し直し、INBOX内の全メールを調べて、未チェックのもの(チェック済みの問題ないメールには背景色をつけて区別)に対してフィルタしています。
色々テキスト置換とかしているのは実行コマンド引数をサニタイズしているためです。
using terms from application "Mail" on perform mail action with messages theMessages for rule theRule try -- 不正なメッセージ一覧が渡されてしまうため、少し待って非同期でINBOX内のメールに対して実行 -- tell me to evaluate(theMessages) do shell script "zsh -c 'sleep 3; osascript ~/Library/Containers/com.apple.mail/Data/Library/Application\\ Scripts/com.apple.mail/eval-with-llm.scpt' &" on error e number n display dialog "eval-with-llm Error: " & e & " (" & n & ")" buttons "OK" default button 1 end try end perform mail action with messages on run tell application "Mail" repeat with theAccount in every account try try -- INBOXを持たないアカウントは無視 set theMessages to messages of mailbox "INBOX" of theAccount end try my evaluate(theMessages) on error e number n display dialog "eval-with-llm Error: " & e & " (" & n & ")" buttons "OK" default button 1 end try end repeat end tell end run on evaluate(message) tell application "Mail" repeat with eachMessage in theMessages if background color of eachMessage is none then set theSubject to subject of eachMessage set theSender to sender of eachMessage set theSubject to my replaceText(theSubject, return, " ") set theSender to my replaceText(theSender, return, " ") set theResult to (do shell script "~/bin/evaluate_mail_sender.sh " & (quoted form of theSender) & " " & (quoted form of theSubject)) if theResult contains "BAD" then move eachMessage to junk mailbox else set background color of eachMessage to blue end if end if end repeat end tell end evaluate on replaceText(target, a, b) set oldDelimiters to AppleScript's text item delimiters set AppleScript's text item delimiters to a set target to text items of target set AppleScript's text item delimiters to b set target to target as string set AppleScript's text item delimiters to oldDelimiters return target end replaceText end using terms from
Mac の Mail.app で設定から 「ルール > ルールを追加」 ですべてのメッセージに対して AppleScript を実行を選び、先ほどのスクリプト名を選ぶことで、受信時に実行されるようになります。
実行時間は1回につき5秒弱 (多数決のため計10-15秒) くらいのようです。精度としてはそこそこの様子。多数決させてもたまに素通りすることもあります。まあ "強い確信がないならOKに倒せ" と指示していますからそんなものでしょう。
なお今多数来ているメールは大体 'Content-Type: text/html; charset="GBK"' などというヘッダがついているので、中国からメールを受け取る機会がないのならこれでフィルタしてしまうのが簡単だったりします。