メールサーバー構築(Postfix / Dovecot / Roundcube / SpamAssassin)で発生したトラブルと解決策
1. Roundcube: Internal Error(INBOX が存在しない) #
症状
ログインは成功するが画面に “Internal Error” が表示される。ブラウザの開発者ツールで確認したレスポンス:
"exec": "this.display_message(\"サーバーエラー: STATUS: Internal error occurred.\", \"error\", 0);"原因
IMAP の STATUS コマンドが失敗。メール未受信のため Maildir の INBOX ディレクトリが存在しなかった。エラーログには何も出力されないため原因特定にブラウザの開発者ツールが必要だった。
解決策
Dovecot に INBOX 自動作成設定を追加した。初回ログイン時に INBOX ディレクトリが自動生成される。
# dovecot 10-mail.conf
namespace inbox {
inbox = yes
mailbox INBOX {
auto = subscribe
}
}2. Postfix: 外部送信タイムアウト(OCI Free Tier) #
症状
postfix/smtp: connect to gmail-smtp-in.l.google.com[...]:25: Connection timed out原因
OCI Free Tier はアウトバウンド port 25 をブロックしている。
解決策
受信専用サーバーに方針変更。
3. SpamAssassin: content_filter ループ #
症状
メール受信時に同一メッセージのログが大量に出力され続ける。
原因
Postfix の content_filter は「受信メールを外部プログラムに渡してスキャンし、処理後に Postfix へ戻す」機構。SpamAssassin はスキャン後に spamc -e sendmail でメールを Postfix に再投入するが、この経路を担当する pickup デーモンにも content_filter 設定が引き継がれているため、再投入メールが再び SpamAssassin に送られ無限ループが発生した。
# 正常系
smtpd → SpamAssassin → spamc -e sendmail → pickup → 配送
# ループ発生時
smtpd → SpamAssassin → spamc -e sendmail → pickup
│
content_filter が再適用される
│
SpamAssassin
│
spamc -e sendmail → pickup → ...(無限ループ)解決策
master.cf の pickup サービスに -o content_filter= を追加し、再投入メールへのフィルタ適用を無効化した。
pickup unix n - y 60 1 pickup
-o content_filter=
-o receive_override_options=no_header_body_checks| オプション | 意味 |
|---|---|
-o content_filter= |
pickup 経由のメールは content_filter を空(無効)にする |
-o receive_override_options=no_header_body_checks |
ヘッダ・本文の再チェックも無効化し、二重処理を防ぐ |
pickup はローカルからの再投入専用デーモンなので、ここで content_filter を切っても外部着信メールには影響しない。smtpd 側の設定はそのまま有効なため、外部メールは引き続き SpamAssassin でスキャンされる。
4. SpamAssassin: Spamhaus ZEN ブロック #
SpamAssassin の概要 #
SpamAssassin はメールをスコアリング方式でスパム判定するフィルタ。様々なルールを適用してスコアを合算し、閾値(デフォルト 5.0)を超えるとスパム判定する。
受信メール
│
▼
ルール群を適用してスコア計算
├─ ヘッダチェック(From/Subject の怪しいパターン等) +1.5
├─ 本文チェック(スパムっぽい文言等) +2.0
├─ DNSBL チェック ← 今回の問題箇所 +3.0
└─ SPF/DKIM チェック -0.1
│
▼
合計スコア ≥ 5.0 → スパム / < 5.0 → 正常メールDNSBL とは #
DNSBL(DNS Block List)は「スパム送信元として知られている IP アドレスのブラックリスト」を DNS で照合できる仕組み。SpamAssassin は受信メールの送信元 IP を DNSBL サーバに問い合わせ、リストに載っていればスコアを加算する。
# 照合の仕組み(送信元 IP: 1.2.3.4 の場合)
DNS クエリ: 4.3.2.1.zen.spamhaus.org
├─ 応答あり → リストに載っている → スコア加算(スパム寄り)
└─ NXDOMAIN → リストにない → スコア変動なしSpamhaus ZEN とは #
Spamhaus が提供する複数のブロックリストを統合した DNSBL。
| リスト | 対象 |
|---|---|
| SBL | 確認済みスパム送信者の IP |
| XBL | マルウェア・ボットネットに乗っ取られた IP |
| PBL | ISP が「メール送信に使うべきでない」と申告した IP(住宅向け回線等) |
ZEN はこれら全てをまとめて一度に照合できるリスト。
症状
dns_block_rule RCVD_IN_ZEN_BLOCKED hit
(This means DNSBL blocked you due to too many queries)原因
Spamhaus ZEN は本来「受信メールの送信元 IP」を照合するサービスだが、クエリ自体の送信元(=自サーバーの IP)もチェックしている。Spamhaus ZEN は無償利用に制限があり、OCI などクラウドプロバイダの IP からの DNS クエリをブロックする。受信メールの内容や送信元 IP とは無関係で、クエリを送る自サーバーの IP が原因。
通常の利用(ISP 等)
自サーバー(IP: A) → DNS クエリ → Spamhaus ZEN
「受信メールの送信元 IP: X がリストに載っているか?」
OCI 環境で起きたこと
自サーバー(OCI IP) → DNS クエリ → Spamhaus ZEN
│
「クエリ元 OCI の IP 自体がブロック対象」
│
dns_block_rule ヒット解決策
local.cf に Spamhaus ZEN への DNS クエリを無効化する設定を追加した。
dns_query_restriction deny zen.spamhaus.orgこれにより SpamAssassin が zen.spamhaus.org へのクエリを送らなくなる。Spamhaus ZEN によるスコアリングは無効になるが、ヘッダ・本文・SPF/DKIM 等の他ルールは引き続き機能する。根本対応としては Spamhaus の有償ライセンス取得やローカルミラーの構築があるが、個人運用の受信専用サーバーであれば無効化で十分。