DELOGs
RSPAMDによる迷惑メールフィルタリング

RSPAMDによる迷惑メールフィルタリング

PostfixとDovecot環境における迷惑メールフィルタリングとしてRSPAMDの導入

初回公開日

最終更新日

サーバ構築編で記載した通り、当サイトでは自前のメールサーバ構築を行なっています。
メールサーバ構築についての確認はこちら...
自前のメールサーバは柔軟な運用ができるメリットがある反面、悩みどころは迷惑メール対策です。やはり汎用的なメールアドレスにはかなりの量の迷惑メールが送りつけられてしまいます。そこで、マストで必要になるのが、フィルタリング機能になります。
迷惑メールフィルタリングのツールは色々とあると思いますが、今回はUbuntuの標準リポジトリにある「RSPAMD」を採用しました。 「RSPAMD」はオープンソースで標準リポジトリにもあるので、信頼性も高いツールと思われます。
RSPAMDの特徴
  • PostfixとDovecotに統合可能
  • DKIM/DMARC/SPFの検証、学習型フィルタ、Bayesian分析、URLフィルタなどを備える
  • Web UIでスコア管理やログも確認できる
いくつかの要素を点数化して、迷惑メールを見極めるフィルタです。

1.「RSPAMD」のインストール

標準リポジトリはバージョンが低いことがあるので、バージョンを調べます。
bash
1apt policy rspamd 2rspamd: 3 インストールされているバージョン: (なし) 4 候補: 3.8.1-1ubuntu3 5 バージョンテーブル: 6 3.8.1-1ubuntu3 500 7 500 http://archive.ubuntu.com/ubuntu noble/universe amd64 Packages
RSPAMDの公式サイトを参照すると2025年6月18日現在の最新バージョンはv3.12.0のようです。 標準リポジトリもそれほど古いバージョンではないですが、せっかくなの最新バージョンをインストールしたいと思います。

最新版をRSPAMD公式リポジトリから導入する手順

○GPGキーの取得と保存(バイナリ形式)
bash
1sudo mkdir -p /etc/apt/keyrings #/etc/apt/keyringsディレクトリがない場合 2curl -fsSL https://rspamd.com/apt-stable/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/rspamd.gpg
すでに何度かこのやり方をしている場合は/etc/apt/keyringsがあると思うので、mkdirはスキップしてバイナリ形式のGPGキーの取得だけ実行すればOKです。
○RSPAMD公式リポジトリの追加
bash
1echo "deb [signed-by=/etc/apt/keyrings/rspamd.gpg] http://rspamd.com/apt-stable/ noble main" | sudo tee /etc/apt/sources.list.d/rspamd.list > /dev/null
これで、最新バージョンがaptで管理できるようになります。
○APTキャッシュ更新とインストール(またはアップグレード)
bash
1sudo apt update 2sudo apt install rspamd
○インストールされたバージョンの確認
bash
1rspamd --version
bash
1Rspamd daemon version 3.12.1 2 3CPU architecture x86_64; features: avx2, avx, sse2, sse3, ssse3, sse4.1, sse4.2, rdrand 4Hyperscan enabled: TRUE 5Jemalloc enabled: TRUE 6LuaJIT enabled: TRUE (LuaJIT version: LuaJIT 2.1.1725453128) 7ASAN enabled: FALSE 8BLAS enabled: FALSE 9Fasttext enabled: FALSE
無事にversion 3.12.1がインストールされました。

2.Postfixとの連携(milter設定)

次にPostfixとの連携をします。私は、なんとなくPostfixは送信だけやっているイメージがあって、受信はDovecotじゃないのかなと思っていたのですが間違いでした。
メール受信の流れの整理
  • 外部メールサーバ(送信元)から送信
    -> Postfix(MTA)が一旦受け取り
    -> (迷惑メール判定)RSPAMD
    -> Dovecot(MDA) でローカル配送
という感じです。したがって「受け取る瞬間に判定して処理する」ためにPostfixとまずは連携させておく必要があります。

Postfix側設定ファイルを編集(main.cf)

bash
1sudo vi /etc/postfix/main.cf
ここでDKIMの設定を行なっている箇所がある場合、下記のようになっていると思います。
bash : main.cf
1# DKIM 2milter_default_action = accept 3milter_protocol = 2 4smtpd_milters = inet:localhost:12301 5non_smtpd_milters = inet:localhost:12301
これを複数milterを同時に使えるように編集します。
diff : main.cf
1- # DKIM 2- milter_default_action = accept 3- milter_protocol = 2 4- smtpd_milters = inet:localhost:12301 5- non_smtpd_milters = inet:localhost:12301 6 7+ # Milter設定:Rspamd(11332)と OpenDKIMなど(12301)両方を指定 8+ milter_default_action = accept 9+ milter_protocol = 6 10+ smtpd_milters = inet:localhost:11332,inet:localhost:12301 11+ non_smtpd_milters = inet:localhost:11332,inet:localhost:12301
milterとは?
Postfixと外部プログラム(例:Rspamd, OpenDKIM, ClamAVなど)をつなぐ「拡張フィルタ用インターフェース」のことです。メールフィルタと置き換えるとわかりやすいかもしれません。下記の用途に使用します。
  • メール受信中にPostfixが milter を通じて外部プロセス(例:Rspamd)にメッセージを送信
  • Rspamdなどが内容を解析して、ヘッダ追加・スコア計算・拒否などの指示を返す
  • Postfixがその内容を取り込んで、迷惑メールをタグ付けしたり拒否したりする
milter_protocolはそのプロトコル、smtpd_miltersはSMTPでの受信(外部やSubmission)の動作、non_smtpd_miltersはローカル送信・内部処理メールの動作をDKIMよりRSPAMDを優先してカンマ区切りで指定しています。 ポート11332はRSPAMDの milterインターフェース(メールフィルタリング)で使用される標準ポートです。
milter_protocol6は拡張バージョンで、BODY途中での中断、ヘッダ追加制御などの機能拡張が含まれます。DKIMの時は古い2で十分でしたが、迷惑メールフィルタに対応するために6を使用します。拡張バージョンでも古いプロトコルしか対応していないmilter(例:OpenDKIM)でも正常に動作するようにPostfixが内部的に調整してくれるようです。
ということで、DKIMとRSPAMDが同居できるようにしたのでPostfixを再起動します。

Postfixを再起動

bash
1sudo systemctl restart postfix

RSPAMD側がポートを開いているか確認

bash
1sudo ss -ltnp | grep 11332
bash
1LISTEN 0 128 127.0.0.1:11332 ...
上記のような出力がでればOKです。127.0.0.1:11332はローカルバインドというやつで、ローカル環境だけでネットワークサービスを公開することを指しています。もし、ローカルバインドできていなけば0.0.0.0:11332のように全てのネットワークで利用可能なポートとなります。これは危険です。今回はPostfixとの内部連携専用でローカル環境で利用するものになるので、FWのポートは開けません。
これでPostfixとの連携は完了です。次にRSPAMDの設定をしていきます。RSPAMDはWeb UIを備えていて、管理画面から設定をしていくこともできますが、今回は諸々セキュリティ面を考えてWeb UIを使わずに設定していきます。

3.RSPAMDの設定

下記の設定を順に行なっていきます。
目的対象ファイル
迷惑メール通知(X-Spam)actions.conf
DKIM署名の検証を行うdkim.conf
精度向上(ベイジアン学習)classifier-bayes.conf
ログ管理logging.inc
Web UI無効化worker-controller.inc

迷惑メール通知(X-Spam)

スコア結果のヘッダ追加と各アクションの境界値設定を行なっていきます。 デフォルト設定は/etc/rspamd/actions.conf にありますが、これは上書きしません。/etc/rspamd/local.d/actions.confを作成して、そこに追加設定を行なっていきます。 ちなみにデフォルト設定は下記のようになっています。
bash
1actions { 2 reject = 15; # Reject when reaching this score 3 add_header = 6; # Add header when reaching this score 4 greylist = 4; # Apply greylisting when reaching this score (will emit `soft reject action`) 5 6 #unknown_weight = 1.0; # Enable if need to set score for all symbols implicitly 7 # Each new symbol is added multiplied by gf^N, where N is the number of spammy symbols 8 #grow_factor = 1.1; 9 # Set rewrite subject to this value (%s is replaced by the original subject) 10 #subject = "***SPAM*** %s" 11 12 .include(try=true; priority=1; duplicate=merge) "$LOCAL_CONFDIR/local.d/actions.conf" 13 .include(try=true; priority=10) "$LOCAL_CONFDIR/override.d/actions.conf" 14}
reject = 15
  • スコアが15以上になったメールは「拒否(REJECT)」される
  • これはSMTPセッション中に550エラーで落とす動作
  • つまり「サーバ側で受信拒否」され、受信者に届かない
add_header = 6
  • スコアが6以上のメールに、X-Spam: や X-Rspamd-Score: などのヘッダを追加
  • ユーザーやフィルターで迷惑メールとして扱いやすくなる
  • この動作にはadd_header = true; の有効化が別途必要なので要注意!
greylist = 4
  • スコアが4以上6未満のメールは一時的に受信拒否(soft reject)
  • 一度拒否された送信サーバは、数分後に再送信してくる
  • 再送信されたら受け入れるという「グレイリスティング」方式。グレイリストはスパムボットを弾きやすいけど、正当なサーバでも多少の遅延が出るのが難点
.include(...) のところにlocal.d/ → マージ方式(merge)override.d/ → 完全上書き(override)という記述もあります。基本はlocal.d/に追記していけばいいことがここでわかります。
bash
1sudo vi /etc/rspamd/local.d/actions.conf
bash : actions.conf
1reject = 15.0; 2add_header = 6.0; 3greylist = 4.0;
スコア設定はデフォルトと同じですが、後から調整しやすいようにここにも記述しておきます。
一旦設定を反映します。
bash
1sudo systemctl restart rspamd

DKIM署名の検証のみ行う

上記の内容を実施した状態なら、すでにopendkim が署名処理を担当している状態です。この場合はDKIM署名の検証のみ行うようにします。
bash
1sudo vi /etc/rspamd/local.d/dkim.conf
bash : dkim.conf
1enabled = true;
これだけです。メール受信時に DKIM-Signature ヘッダがあると、その署名の検証を行いスコアに反映します。 ちなみ/etc/rspamd/local.d/dkim.conf /etc/rspamd/modules.d/dkim.confが読み込んでマージしてくれます。
一旦設定を反映します。
bash
1sudo systemctl restart rspamd

精度向上(ベイジアン学習)

ベイジアン学習(Bayes)とは、メール本文の単語やシンボルを学習し、「スパムっぽい内容」「ハムっぽい内容」を識別する仕組みです。これによって スパム判定の精度が徐々に向上し、自動学習もしてくれます。 「ハム」というのは、スパムに対比して、正当なメールという意味合いでジョーク的に名付けられた呼称です。
RSPAMDのBayes(ベイジアン)学習を有効にするには、Redis(レディス)が必須です。Redis(レディス)は、超高速な「インメモリ型のデータベース」で、学習したスパム/ハムの単語統計を保存したり、スパム傾向のある送信元を追跡するために利用されます。学習結果を保存しておく場所という感じです。
ちなみに、学習以外でもRSPAMDはブラックリストを配信してくれていて、デフォルトでそれを受け取る設定になっています。なので、これを補強していくのが学習という感じです。
○Redisのインストール
bash
1sudo apt update 2sudo apt install redis-server
インストール後、サービスを有効化&起動:
bash
1sudo systemctl enable --now redis-server
状態確認:
bash
1sudo systemctl status redis-server
○RedisをRSPAMDに認識させる
bash
1sudo vi /etc/rspamd/local.d/redis.conf
bash : redis.conf
1servers = "127.0.0.1";
○Bayes学習を有効
以下のファイルを作成・編集して、Bayes学習を有効にしていきます。
bash
1sudo vi /etc/rspamd/local.d/classifier-bayes.conf
bash : classifier-bayes.conf
1backend = "redis"; 2servers = "127.0.0.1:6379"; 3new_schema = true; 4min_tokens = 11; 5min_learns = 200; 6 7autolearn { 8 spam_threshold = 6.0; 9 ham_threshold = -0.5; 10 check_balance = true; 11 min_balance = 0.9; 12}
backend = "redis";
  • 学習データの保存先を Redis に指定
  • デフォルトは sqlite3 だが、パフォーマンス・柔軟性の点で Redis の方が推奨されています
servers = "127.0.0.1:6379";
  • Redis の接続先。今回はローカルホスト上のポート 6379 を使用
new_schema = true;
  • 新しいBayesスキーマ(トークンごとにハム/スパムスコアを個別に記録)を使用
  • より正確な判定ができるため、必ず true を推奨
min_tokens = 11;
  • 1通のメールに含まれるトークン(単語等)が11個以上でないと学習対象にしない
  • ノイズの多い短いメール(例:「了解です」)などを除外するため
min_learns = 200;
  • 学習が有効になるまでに必要な最低件数(ハム/スパムそれぞれ)
  • 精度確保のため、最低200件は溜めてから分類に反映されるようにしている
自動学習設定(autolearn)
  • spam_threshold = 6.0 : スコア6以上のメールをスパムとして学習
  • ham_threshold = -0.5 : スコア-0.5以下のメールをハムとして学習
  • check_balance = true : スパム・ハム学習数のバランスをチェック
  • min_balance = 0.9 : スパムとハムの学習数の比率が±10%以内でなければ、自動学習しない(片寄り防止)
○オプションの有効化
せっかくなので、Redis(レディス)依存のオプションも有効にしていきます。下記のようなものがあります。
モジュール名説明特徴
history_redisWeb UIでスキャン履歴(Statistics→Scan history)が表示されるようになるUIでの可視性が向上し、学習や調整に便利
greylistグレイリスト制御(初回だけ一時拒否)すでに使っている設定なので、状態が正しく反映されるように
ratelimit同一送信者などの送信頻度を制限(DoS/Bot対策)不正アクセス対策として有効。ただし誤判定リスクも少しあり
url_redirectorURL短縮サービスの展開(spamのURLを検出しやすくする)実用的で誤判定リスクは低め。Spamリンク判定強化に寄与するが、URLを内部展開するのでマルウェア感染を考慮して慎重に
neuralスパム/ハム判定に機械学習モデルを用いる(ニューラルネットワーク)精度の高い判定が可能になるが、学習には十分なデータ量とRedisが必要。構築と維持がやや高度で中~上級者向け
replies過去に送信したメールへの返信かどうかを検出し、スパム誤判定を防ぐ正常な返信メールをスパムとして扱わないようにでき、誤判定を減らせる。効果的で安全性も高くおすすめ
上記のうち、誤判定リスクの少ないものを下記のように設定しました。
bash
1sudo vi /etc/rspamd/local.d/options.inc
bash : options.inc
1modules { 2 greylist = true; 3 history_redis = true; 4 replies = true; 5}
○古いデータの掃除:bayes_expiry.conf
Bayes学習データは 増え続けます(メールに含まれる単語やパターン)。これは、Redisに保存されますが、無限に保存するとメモリを圧迫することになってしまいます。精度維持とリソース節約のため、古くて使われないデータを自動で削除する設定が必要になります。
bash
1sudo vi /etc/rspamd/local.d/bayes_expiry.conf
bash : bayes_expiry.conf
1expire = true; 2expire_days = 90;
expire = trueで期限設定を有効にして、expire_days = 90で期限を90日にしています。最終使用から90日経った学習データは自動で削除されます。
一旦設定を反映します。
bash
1sudo systemctl restart rspamd
○手動学習:learn_spam / learn_ham
自動で学習してくれますが、手動でも学習させることが可能です。手動学習は後ほど導入Web UI経由でも可能です。
bash
1# スパム学習 2rspamc learn_spam < ~/mail/spam1.eml 3 4# ハム学習 5rspamc learn_ham < ~/mail/normal1.eml
メールのクライアントツールで保存したデータをサーバへアップして上記のコマンドで読み込ませることで学習してくれます。ちなみ、学習させるメールは設定中のメールサーバで受信したメールじゃなくてもOKです。Gmailの迷惑メールフォルダにあるメールなどで大丈夫です。
○学習結果の確認方法:
bash
1rspamc stat
learned: XX が増えて、Statfile: BAYES_SPAM / HAM の件数が蓄積されていくことが確認できます。

ログ管理

ログはデフォルトで/var/log/rspamd/rspamd.logに出力されています。ログローテーションもUbuntuが自動でやってくれます。なので、ローカル設定を行わなくても、特に問題はないです。下記は少しカスタマイズするなら程度に捉えてください。
bash
1sudo vi /etc/rspamd/local.d/logging.inc
bash : logging.inc
1type = "file"; 2filename = "/var/log/rspamd/rspamd.log"; 3level = "notice"; 4log_buffered = true; 5log_re_cache = false; 6log_urls = false; 7log_usec = true;
level = "notice";
ログレベルになります。デフォルトではinfoになります。"notice" と書くと、「notice以上の重要度のログだけ出力する」という意味になります。
ログレベル一覧(重要度の低い順)
レベル説明出力内容の例
debug詳細なデバッグ情報(開発者向け)ルール評価の内部状態など
info通常の情報起動時設定、フィルタ処理の流れなど
notice注意が必要な情報(デフォルト)フィルタの適用・重要イベント
warning警告設定ミスや軽微なエラーなど
errorエラー処理の失敗、重大な不具合など
critical致命的エラーサーバが動作不能な状態
log_buffered = true;
  • ログ出力をバッファリング(まとめ書き)する
  • ディスクへの書き込みを減らす
  • リアルタイム書き込みでないので、クラッシュ時に直前のログが失われる可能性がある
log_re_cache = false;
  • 正規表現キャッシュのログを出すかどうか
  • true にすると、正規表現キャッシュヒット・ミスの情報を出す(非常に詳細)
log_urls = false;
  • メール内のURLをログに出すかどうか
  • true にすると、各メールに含まれるURLがログに出るがログは肥大化する
log_usec = true;
  • ログのタイムスタンプにマイクロ秒単位を含めるかどうか
  • true にすると、タイミングの精密な解析に便利(たとえば、処理にかかった時間など)
一旦設定を反映します。
bash
1sudo systemctl restart rspamd

4. Web UI(controller)をSSHトンネルで利用する

セキュリティ面を考慮して、SSHトンネル経由のみでWeb UIにアクセスできるようにします。 スコアチューニングにはやはりGUIがあった方が便利です。
まずは、Web UIにアクセスする際のパスワードを作成します。
bash
1rspamadm pw
上記でパスワードをハッシュ化してくれます。これをメモっておきます。このあと利用します。
bash
1sudo vi /etc/rspamd/local.d/worker-controller.inc
bash : worker-controller.inc
1enabled = true; 2bind_socket = "127.0.0.1:11334"; 3password = "$2$..."; #ここに先ほど作成したハッシュ化パスワードを記述します
一旦設定を反映します。
bash
1sudo systemctl restart rspamd
ローカルPCでSSHトンネルを通します
zsh
1ssh -L 11335:localhost:11334 -N -p sshのポート番号 -i "~/sshの認証ファイル.pem" SSHユーザ名@サーバIP
トンネルが通ったら、ブラウザでhttp://localhost:11335/にアクセスします。 RSPAMDのWebUI
上記のようなUIを通して、さまざま設定や管理ができるようになります。Web UIの詳しい説明を「RSPAMD公式サイトのドキュメント」で探したのですが、見つかりませんでした。。ただ、各メニューの内容を見ると大体の内容はわかるかと思います。

5.チューニングとルール管理について

これが最後のフェーズになります。RSPAMD が各チェック結果にどれだけの「重み(スコア)」を与えるかを調整していきます。といっても、最初はデフォルト設定のままでいいかなと思っています。 WebUIではSymbolsというメニューから現在のスコア設定が参照できます。
RSPAMDのSymbols
かなり細く設定してくれているのがわかります。これは下手に変更するより、このまま運用して、その結果を踏まえて調整を行う方がいいかなと思っています。
それで、ここが重要なのですが、「Web UI」は確認用に使います。実際の設定は、ファイルベースで行うようにします。「Web UI」で値を変更した場合、/etc/rspamd/local.d/配下のファイルは変更されません。 /var/lib/rspamd/dynamic/*という別の領域に保存されます。WebUIしか使わないという選択をする場合は、これで良いですが、私のように主にファイルベースで編集する場合、うっかりWebUIで編集してしまうと、どちらで編集したかわからなくなり、混乱の元になってしまいます。そこで、設定編集は/etc/rspamd/local.d/配下のファイル、内容確認やログ確認はWebUIと利用方法を分けることにしています。/etc/rspamd/local.d/配下のファイルを編集すれば、WebUIの表示内容も変化する仕様のようです。
というわけで、運用する中で、実際調整したいとなった時にどうするか? 下記のようにします。
/etc/rspamd/local.d/〇〇_group.conf(policies_group.conf 等)というカスタムチューニングファイルを作成するようにします。このグループ名のところは/etc/rspamd/group.confで定義済みのグループ名である必要があります。「Web UI」の「Symbols」タブで表示されている「Group」とは異なりますので注意が必要です。
まず、カスタムしたい「symbol」がどのグループに属するかを調べます。/etc/rspamd/scores.d/に実際のスコア定義ファイルがありますので、ここを検索します。
例えばARC_REJECTというシンボルについてカスタムしたいと思ったら:
bash
1grep -rA4 ARC_REJECT /etc/rspamd/scores.d/
bash
1/etc/rspamd/scores.d/policies_group.conf: "ARC_REJECT" { 2/etc/rspamd/scores.d/policies_group.conf- weight = 1.0; 3/etc/rspamd/scores.d/policies_group.conf- description = "ARC checks failed"; 4/etc/rspamd/scores.d/policies_group.conf- groups = ["arc"]; 5/etc/rspamd/scores.d/policies_group.conf- }
上記のように返ってきてpolicies_groupに記述されていることがわかります。
bash
1sudo vi /etc/rspamd/local.d/policies_group.conf
このファイルに、例えば下記のようにsymbols {} ブロックを作って、そこにスコアを定義すればOKです。
bash : arc_group.conf
1symbols { 2 "ARC_REJECT" { 3 weight = 2.0; 4 } 5}
bash
1# 構文チェック 2sudo rspamadm configtest 3 4# リスタート 5sudo systemctl restart rspamd
以上で、「RSPAMD」の導入は完了です。
この記事の執筆・編集担当
DE

松本 孝太郎

DELOGs編集部/中年新米プログラマー

ここ数年はReact&MUIのフロントエンドエンジニアって感じでしたが、Next.jsを学んで少しずつできることが広がりつつあります。その実践記録をできるだけ共有していければと思っています。