第22章 メール配送フィルタとメールボックスアクセス(Sieve/Dovecot)

LPIC-2 211.2〜211.3 相当

前章ではPostfixによる送信の基本を扱いました。ここでは受信したメールをどう振り分けるか(Sieve)、そしてユーザーがメールボックスにアクセスするための仕組み(Dovecot)を掘り下げて扱います。

Dovecotの役割

Dovecotは、ユーザーがメールクライアントからメールボックスを閲覧するためのIMAP/POP3サーバーです。Postfixが受け取ったメールをメールボックスに配送し、Dovecotがそれをユーザーに届けるという分担になります。

$ sudo systemctl status dovecot
● dovecot.service - Dovecot IMAP/POP3 email server
     Loaded: loaded (/lib/systemd/system/dovecot.service; enabled; preset: enabled)
     Active: active (running) since Fri 2026-08-21 09:15:02 JST; 2h 30min ago
    Process: 4210 ExecStartPre=/usr/sbin/dovecot -F -c /etc/dovecot/dovecot.conf (code=exited, status=0/SUCCESS)
   Main PID: 4218 (dovecot)
      Tasks: 5 (limit: 4649)
     Memory: 12.3M
        CPU: 340ms
     CGroup: /system.slice/dovecot.service
             ├─4218 /usr/sbin/dovecot
             ├─4220 dovecot/anvil
             ├─4221 dovecot/log
             └─4222 dovecot/config
$ doveconf -n     # 現在有効な設定を表示
# 2.3.21 (7e8b9aa6f4)
# OS: Linux 6.6.32-1 x86_64 Ubuntu 24.04.1 LTS
mail_location = maildir:~/Maildir
protocols = imap pop3 lmtp
ssl = required
ssl_cert = </etc/ssl/certs/mail.crt
ssl_key = </etc/ssl/private/mail.key

この行のこの値に注目: systemctl statusのCGroupに列挙されているdovecot/anvil・dovecot/log・dovecot/configは、Dovecotがマスタープロセスから機能ごとに分離した子プロセスを起動するアーキテクチャを採用していることを示します。doveconf -nの出力は、doveconf -nという名前の通り「既定値から変更された設定だけ」に絞られているため、この行数だけを見れば実際にどこをカスタマイズしたのかが一目瞭然になります。

メールボックスの保存形式には、伝統的なmbox(1ファイルにすべてのメールを連結して格納)と、より新しいMaildir(1メール1ファイルとしてディレクトリに格納)があります。Maildir形式は、複数プロセスが同時にアクセスしてもファイルロックの競合が起きにくく、メールの一部が壊れても他のメールに影響しないという利点があるため、現在の新規構築ではMaildirが選ばれることがほとんどです。

プロトコル特徴
POP3メールをクライアント側にダウンロードして削除するのが基本の動作。1台の端末だけでメールを読む場合に単純
IMAPメールはサーバー側に置いたまま操作する。複数端末(スマートフォンとPCなど)で同じメールボックスを参照する場合に適している

Dovecotの設定ファイル構成

Dovecotの設定は/etc/dovecot/以下に分割されたファイル群で構成されます。メインのdovecot.confからconf.d/以下の機能ごとのファイルが!includeで読み込まれる構造です。主要なファイルの内容を、コメント付きの完全な例として示します。

/etc/dovecot/dovecot.conf
protocols = imap pop3 lmtp     # 有効にするプロトコル(IMAP・POP3・ローカル配送用のLMTP)
!include conf.d/*.conf         # conf.d以下の全設定ファイルを読み込む
/etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:~/Maildir   # Maildir形式、各ユーザーのホーム配下に保存
# mbox形式の場合は mail_location = mbox:~/mail:INBOX=/var/mail/%u のように書式が異なる
/etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = yes    # TLSで保護されていない平文認証を拒否する
auth_mechanisms = plain login   # 許可する認証方式(TLS保護下でのみplain/loginを許可)
!include auth-system.conf.ext   # PAM等、システム標準の認証設定を読み込む
/etc/dovecot/conf.d/10-ssl.conf
ssl = required                              # 暗号化されていない接続を拒否する
ssl_cert = </etc/ssl/certs/mail.crt         # 証明書(<はDovecot独自の「ファイル内容を読み込む」構文)
ssl_key = </etc/ssl/private/mail.key        # 秘密鍵
ssl_min_protocol = TLSv1.2                  # 許可する最低限のTLSバージョン
/etc/dovecot/conf.d/10-master.conf(抜粋)
service imap-login {
  inet_listener imap {
    port = 143
  }
  inet_listener imaps {
    port = 993
    ssl = yes
  }
}
service pop3-login {
  inet_listener pop3 {
    port = 110
  }
  inet_listener pop3s {
    port = 995
    ssl = yes
  }
}
service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

service auth内のunix_listenerが、前章のPostfixのsmtpd_sasl_path = private/authに対応する、Postfix用のSASL認証ソケットの定義です。ここでPostfixユーザー・グループに読み書き権限を与えることで、PostfixがこのソケットごしにDovecotへ認証を委譲できるようになります。

/etc/dovecot/conf.d/20-lmtp.conf
protocol lmtp {
  mail_plugins = $mail_plugins
}
service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
  }
}

LMTP(Local Mail Transfer Protocol)は、PostfixからDovecotへメールを受け渡すための、SMTPに似た軽量なプロトコルです。伝統的なUnixのlocal配送に比べ、1回の接続で複数の宛先をまとめて処理できるなど効率面で優れており、現在のDovecot連携では標準的な選択肢になっています。

doveconf -nとdoveconf -aの違い

コマンド用途
doveconf -n既定値と異なる(管理者が変更した)設定のみを表示する。設定の見通しがよく、サポートへの報告時にもよく使われる
doveconf -a既定値も含めた全設定項目を表示する。特定パラメータの現在の実効値を細部まで確認したい場合に使う
$ doveconf -n | grep ssl
ssl = required
ssl_cert = </etc/ssl/certs/mail.crt
ssl_min_protocol = TLSv1.2

doveadmの主要サブコマンド

サブコマンド用途
doveadm user <user>指定ユーザーのuserdb情報(メールボックスの場所、UID/GIDなど)を確認する
doveadm auth test <user>指定ユーザーの認証(パスワード)が正しく通るかをテストする
doveadm mailbox list -u <user>指定ユーザーが持つメールボックス(フォルダ)の一覧を表示する
doveadm search条件を指定してメールを検索する
doveadm fetch検索条件に一致したメールの内容やヘッダーを取得する
doveadm expunge検索条件に一致したメールを完全に削除する
doveadm quota get -u <user>指定ユーザーのメールボックス使用量・クォータ状況を確認する
$ doveadm user alice
field        value
uid          5001
gid          5001
home         /home/alice
mail         maildir:~/Maildir

$ doveadm auth test alice
Password:
passdb: alice auth succeeded

$ doveadm mailbox list -u alice
INBOX
Sent
Trash
Newsletters

$ doveadm search -u alice mailbox INBOX seen
box=INBOX uid=1023
box=INBOX uid=1024
box=INBOX uid=1030
$ doveadm expunge -u alice mailbox Trash before 30d   # ゴミ箱内の30日より古いメールを削除(正常時は無出力)
$ doveadm quota get -u alice
Quota name  Type    Value  Limit  %
STORAGE     STORAGE 128000 512000 25

この行のこの値に注目: doveadm searchの出力にあるuid=は、そのメールボックス内でのメール固有の番号(IMAP UID)で、この番号を使ってdoveadm fetchで個別のメール内容を取得できます。doveadm quota getの%列(この例では25%)が100に近づいている場合、そのユーザーのメールボックスがクォータ上限に近づいていることを示し、新着メールの受信拒否につながる前に容量整理や上限緩和を検討する目安になります。

Dovecotのユーザー認証(passdb/userdb)

Dovecotは、ユーザーが誰であるかを確認する「passdb」(パスワード確認)と、そのユーザーのメールボックスの場所やUID/GIDを決める「userdb」(ユーザー情報)という、2つの独立した仕組みでユーザーを扱います。

/etc/dovecot/conf.d/10-auth.conf などの一部
passdb {
    driver = pam
}
userdb {
    driver = passwd
}
driver用途
pamLinuxのシステムアカウント(PAM経由)で認証する
passwd-fileDovecot専用のパスワードファイルで認証する(システムアカウントと分離したい場合)
ldapLDAPサーバーに問い合わせて認証する
sqlMySQLなどのデータベースに問い合わせて認証する(大規模なホスティング環境向け)

passdbとuserdbは異なるdriverを組み合わせることも可能です(例:認証はLDAPで行うが、メールボックスの場所は固定のルールで決めるなど)。この分離により、認証方式を変更してもメールボックスの管理方法には影響を与えない、柔軟な構成が可能になります。

Sieveとは何か

Sieveは、受信したメールを条件に応じて自動的に振り分けるための、標準化(RFC 5228)されたスクリプト言語です。DovecotではPigeonholeというプラグインを通じてSieveを実行できます。

procmailとの違い(安全な言語である理由): Sieveが登場する以前は、procmailというツールが同様のメールフィルタリング用途で広く使われていました。procmailの独自ルール言語は事実上任意の外部コマンドへメールをパイプできる強力さを持つ一方、Sieveは意図的に「Turing完全ではない」言語として設計されています。ループ構文や任意プログラムの実行手段を持たないため、無限ループやリソース枯渇を起こすスクリプトを書くこと自体ができません。この安全性の高さゆえに、Sieveはエンドユーザー自身にWebメールやSieveエディタから直接ルールを編集させても、サーバー側のリスクが小さく済みます。

DovecotでのSieveの有効化

Sieveを使うには、メール配送を担うプロトコル(ldaまたはlmtp)にsieveプラグインを追加します。

/etc/dovecot/conf.d/20-lmtp.conf または 90-sieve.conf
protocol lmtp {
    mail_plugins = $mail_plugins sieve
}
protocol lda {
    mail_plugins = $mail_plugins sieve
}

ユーザーが現在有効にしているSieveスクリプトは~/.dovecot.sieve(実体はシンボリックリンクで、~/sieve/配下の実際のスクリプトファイルを指すことが多い)です。管理者が全ユーザー共通で適用したいルールがある場合は、ユーザー自身のスクリプトの前後に、管理者管理のグローバルスクリプトを挟み込めます。

90-sieve.conf での設定
sieve_before = /etc/dovecot/sieve/before.d/    # ユーザーのスクリプトより前に必ず実行(例:明らかなスパムの隔離)
sieve_after  = /etc/dovecot/sieve/after.d/     # ユーザーのスクリプトの後に実行(例:フォールバック処理)

WebメールやメールクライアントのプラグインからシェルアクセスなしにSieveスクリプトを編集・アップロードできるようにする、ManageSieveプロトコル(RFC 5804、既定ポート4190)用のサービスも用意されています。

conf.d/20-managesieve.conf
service managesieve-login {
  inet_listener sieve {
    port = 4190
  }
}

Sieveの基本構文

スクリプトの先頭ではrequireで使用する拡張機能を宣言し、if/elsif/elseで条件分岐を書きます。

基本構文の骨格
require ["fileinto", "envelope", "reject", "vacation"];

if header :contains "subject" "[SPAM]" {
    fileinto "Junk";
} elsif address :is "from" "boss@example.com" {
    fileinto "Important";
} else {
    keep;
}
条件(テスト)意味
header指定したヘッダーフィールドの値を検査する
addressFrom/Toなどのアドレス系ヘッダーから、アドレス部分だけを抜き出して検査する
envelopeSMTPのエンベロープ情報(MAIL FROM/RCPT TOで実際にやり取りされた値)を検査する
sizeメール全体のサイズを検査する
exists指定したヘッダーが存在するかどうかを検査する
allof複数の条件をすべて満たすか(AND)を検査する
anyof複数の条件のいずれかを満たすか(OR)を検査する
not条件の結果を反転する
比較演算子意味
:is完全一致
:contains部分一致(指定した文字列を含むか)
:matchesワイルドカード(*・?)を使ったパターン一致
:overサイズが指定値を超える(sizeテストで使用)
:underサイズが指定値未満(sizeテストで使用)
アクション意味
keep既定の受信トレイにそのまま保持する
fileinto "フォルダ名"指定したフォルダへ移動する
redirect "アドレス"別のメールアドレスへ転送する
reject "理由"送信者にエラーを返して受信を拒否する
discardエラーを返さず、静かに破棄する
stopそれ以降のルール評価を打ち切る
addflag "フラグ"メールに\Seenや\FlaggedなどのIMAPフラグを立てる

実用的なフィルタ例

例1:件名に[SPAM]を含むものをJunkフォルダへ
require ["fileinto"];
if header :contains "subject" "[SPAM]" {
    fileinto "Junk";
    stop;
}
例2:特定の送信者からのメールをフォルダ分け
require ["fileinto"];
if address :is "from" "newsletter@example.com" {
    fileinto "Newsletters";
} elsif address :contains "from" "@partner.example.com" {
    fileinto "Partners";
}
例3:1MBを超えるメールを別フォルダへ
require ["fileinto"];
if size :over 1M {
    fileinto "LargeMail";
}
例4:List-Idヘッダーでメーリングリストを振り分け
require ["fileinto"];
if header :contains "list-id" "<dev-list.example.com>" {
    fileinto "Lists.Dev";
}
例5:不在通知(vacation)
require ["vacation"];
if not header :contains "subject" "[SPAM]" {
    vacation
        :days 7
        :subject "休暇のため返信が遅れます"
        :addresses ["alice@example.com", "alice.smith@example.com"]
        "現在休暇をいただいております。緊急の場合はお電話にてご連絡ください。";
}

この行のこの値に注目::days 7は、同じ送信者に対しては7日間隔でしか自動返信を送らないという設定で、短期間に同じ相手へ何度も自動応答を送り続ける事態を防ぎます。:subjectは自動返信メール自体の件名を指定します。:addressesには、自分が受け取りうる複数のメールアドレス(エイリアスなど)を列挙しておく必要があります。これを指定し忘れると、エンベロープ宛先が主アドレスと一致しない場合にvacationが発動しないことがあります。

sievecによるコンパイルと構文チェック

sievecは、Sieveスクリプトを事前にバイナリ形式(.svbin)へコンパイルし、構文エラーがないかを静的にチェックするツールです。特に管理者がsieve_before/sieve_afterのようなグローバルスクリプトを配置する際、実運用中の配送処理でパースエラーが起きるリスクを事前に減らせます。

$ sievec /etc/dovecot/sieve/before.d/spam-check.sieve
# 構文エラーがなければ何も出力されず、同名の.svbinファイルが生成される

$ sievec broken.sieve
broken.sieve: line 5: error: unexpected token '}'
# 構文エラーがあれば、行番号付きでエラー内容が表示される

procmailの概要

procmailは、Sieve登場以前から使われてきた、正規表現ベースの独自ルールファイル(~/.procmailrc)によるメールフィルタリングツールです。レシピと呼ばれる単位でルールを記述します。

procmailのレシピ書式の例
:0 flags: lockfile
* ^Subject:.*SPAM
spam-folder

:0は新しいレシピの開始を示す記号です。flagsには、ヘッダーのみを検査対象にするH、本文も検査対象にするB、マッチしても以降のレシピの評価を継続するc(コピーを作る)などを指定できます。lockfileは、複数のprocmailプロセスが同時に同じメールボックスを操作しないよう排他制御に使うロックファイル名です(省略時は自動生成)。*で始まる行が条件(正規表現)で、複数行書くとすべての条件を満たす場合にのみマッチするAND条件になります。最後の行がアクションで、ディレクトリ/mboxファイルへのパスを書けば配送先指定、|で始めれば外部コマンドへのパイプになります。

procmailが非推奨になりつつある理由: procmail自体のメンテナンスは長期間ほぼ停止しており、新機能や積極的なセキュリティ修正が期待しにくい状況です。加えて、正規表現ベースの独自ルールは複雑な条件を書くほど可読性が低下しやすく、任意の外部コマンドへ自由にパイプできる強力さは、エンドユーザーが自分の.procmailrcを自由に編集できる環境では、暴走プロセスやリソース枯渇を招くリスクにもなります。標準化され、意図的に安全な言語として設計されたSieveの方が、これらの懸念が小さく済みます。新規構築では、特別な理由がない限りSieveを選ぶのが現在の主流です。

Courierについて

Dovecotとは別系統の歴史あるメールサーバー実装群として、Courier(Courier-IMAPやCourier-MTAなど)も存在します。LPIC-2の出題範囲では、Courierの詳細な設定手順まで問われることは多くありませんが、「DovecotやPostfix以外にもCourierという選択肢がある」という存在自体を知っておくと、実務や試験で名前が挙がった際に戸惑わずに済みます。現在の新規構築ではDovecot+Postfixの組み合わせが主流ですが、既存システムの引き継ぎ・移行作業などでCourierベースの環境に遭遇する可能性は残っています。

確認クイズ

Q1. 複数プロセスが同時にアクセスしてもファイルロックの競合が起きにくい、1メール1ファイル形式のメールボックス保存形式はどれですか?

解説: Maildirは1メール1ファイルとしてディレクトリに格納する形式で、mboxに比べてロック競合や部分破損のリスクが低いため、現在の新規構築で主流です。

Q2. Dovecotの設定ファイルで、PostfixからのSASL認証を受け付けるためのUnixソケットが定義されているのはどれですか?

解説: conf.d/10-master.confのservice auth内のunix_listenerが、PostfixのsmtpdSASL認証を受け付けるためのソケットを定義しています。

Q3. doveconf -aとdoveconf -nの違いとして正しいものはどれですか?

解説: doveconf -nは既定値と異なる設定のみを簡潔に表示し、doveconf -aは既定値も含めた全設定項目を表示します。

Q4. doveadmのサブコマンドのうち、指定ユーザーの認証(パスワード)が正しく通るかをテストするものはどれですか?

解説: doveadm auth testは、指定したユーザーの認証が正しく通るかをテストします。doveadm userはuserdb情報の確認、doveadm mailbox listはメールボックス一覧の表示に使います。

Q5. Dovecotで、ユーザーが誰であるかを確認する仕組みを何と呼びますか?

解説: passdbはパスワード確認(認証)を担う仕組みで、userdbはメールボックスの場所やUID/GIDなどのユーザー情報を決める仕組みです。この2つは独立して組み合わせられます。

Q6. Sieveが、procmailと比べて「安全な言語」とされる主な理由はどれですか?

解説: Sieveは意図的にTuring完全ではない言語として設計されており、無限ループやリソース枯渇を起こすスクリプトを書くこと自体ができません。この安全性により、エンドユーザーに直接編集させてもリスクが小さく済みます。

Q7. DovecotでSieveを使うために、mail_pluginsにsieveを追加する必要があるプロトコルはどれですか?

解説: メール配送を担うlda(Local Delivery Agent)またはlmtp(Local Mail Transfer Protocol)にsieveプラグインを追加することで、配送時にSieveスクリプトが評価されるようになります。

Q8. sieve_beforeとsieve_afterの役割の違いとして正しいものはどれですか?

解説: sieve_beforeはユーザー自身のスクリプトが実行される前に、sieve_afterは実行された後に、管理者が管理するグローバルなSieveスクリプトを実行するための設定です。

Q9. Sieveの比較演算子のうち、サイズが指定値を超えるかどうかを検査するものはどれですか?

解説: :overはsizeテストと組み合わせて、メールサイズが指定値を超えるかどうかを検査します。:underはその逆(指定値未満)です。

Q10. vacationアクションの:addressesオプションを指定し忘れた場合に起きがちな問題はどれですか?

解説: :addressesには自分が受け取りうる複数のメールアドレス(エイリアスなど)を列挙する必要があり、これを指定し忘れると一部の宛先パターンでvacationが発動しないことがあります。

Q11. Sieveスクリプトの構文エラーを事前に静的チェックするために使うコマンドはどれですか?

解説: sievecは、Sieveスクリプトをバイナリ形式にコンパイルする過程で構文エラーの有無を静的にチェックするツールです。

Q12. procmailのレシピで、複数の条件行(*で始まる行)を重ねて書いた場合の評価方法はどれですか?

解説: procmailのレシピで複数の条件行を重ねて書くと、すべての条件を満たす場合にのみそのレシピがマッチするAND条件になります。