インフィニットループ 技術ブログ

2015年07月01日 (水)

著者 : mizuno_as

DovecotとSieveを使ったメールのサーバーサイドフィルタリング

炎暑の候、みなさまのサーバーもいっそうご隆昌のことと慶賀の至りに存じます。こんにちは、mizuno_asです。
みなさん、メール使ってますか? 最近の開発現場ではコミュニケーションのコストを下げるため、SkypeやSlackなどのチャットツールを使うのが一般的かもしれませんね。しかしいくらレガシーだといっても、そうそう簡単にはメールを捨てられないのが現実です。特にサービスを運営していたりすると、社内にメールサーバーの一台や二台は、まだあるのではないでしょうか。

Photo by greg westfallCC BY 2.0
とはいえこのご時世。スマートフォンやタブレットを含む、複数のデバイスを横断してお仕事をすることは珍しくありません。デバイスに束縛されないためには、オンラインでシームレスにデータを同期できる仕組みが必要不可欠です。ことメールに関して言えば「Gmailに丸投げ」してしまうのが一番簡単で、実際に転送設定をしている人も多いかと思います。しかし全メールを転送するのは色々と問題があるため ((メールの数が多くなりすぎる、SPAMまで転送してしまう、SPAM転送によってメールサーバーがGoogleから転送拒否される、などなど。)) 、転送するのは本当にモバイルから読む必要があるメールだけに限りたいところです。
ほとんどのMUAにはメールのフィルタリング機能が実装されています ((フィルターでメールをフォルダー分けするのはメール整理の基本ですよね。読みたくもないメールを効率的にゴミ箱に直行させることができる素晴しい機能です。)) 。ではフィルターを使って、受信したメールを転送してみましょう。

……
………
いやいや、メール転送のためだけに、四六時中オフィスのPCでMUAを起動させっぱなしにしておくというのはあまりエコではありませんし、特定のクライアントで一度受信するというのも筋悪です。そこでDovecot LDA(Local Delivery Agent)と、メールのフィルタリング用言語Sieveを使い、メールをサーバーサイドでフィルタリングしてみました。

メールサーバーの構築

まずUbuntu 14.04 LTSを普通のメールサーバーに仕立てましょう。MTAにはPostfix、IMAPサーバーにはDovecotを利用します ((サーバーにグローバルIPアドレスを設定したり、DNSのMXレコードを設定したりといった話は省略します。)) 。

$ sudo apt-get install postfix dovecot-imapd

dovecot-coreパッケージのインストール時に、debconfによって自己署名証明書を作成するかどうか質問されます。SSL証明書を購入している本番環境の場合はもちろんそれを使用するのですが、テスト目的などの場合はここで「Yesを選択」→「CNを入力」と進み、自己署名証明書を作成しておきましょう ((ここで作成された自己署名証明書は/etc/ssl/certs/ssl-cert-snakeoil.pem、秘密鍵は/etc/ssl/private/ssl-cert-snakeoil.keyに保存されます。ちなみにSnake Oilとはうさんくさいインチキ商品を指す言葉(日本で言うガマの油でしょうか)で、そこから転じてセキュリティ業界では、サンプル認証局の名前に使われているようです。)) 。

続くpostfixパッケージのインストール時には、メールサーバーのタイプと名前を入力する必要があります。メールサーバータイプは「Internet Site」、System mail nameにはメールアドレスのドメインパートをFQDNで入力してください ((ちなみにメールサーバータイプにlocal onlyを指定すると、文字通りローカルからのみ送信が可能で、外部へのsmtpやリレーはできないサーバーが簡単に作れます。具体的にはmain.cfのinet_interfacesにloopback-only、default_transportとrelay_transportにerrorが設定されます。)) 。ここで入力した内容は、main.cfのmyhostnameとmydestinationに含まれます。
この状態でもう(例えばmailコマンドなどから)メールの送信は可能になっています ((つまりシステムからメールを送信するだけのサーバーであれば、これだけでインストール完了です。inet_interfacesを絞るなどの対応はした方がいいかもしれませんが……。)) が、外部のMUAからもメールの送受信ができるよう、PostfixとDovecotにいくつかの設定を追加します。
まずSMTPサーバーの認証です。smtpd_relay_restrictionsにpermit_sasl_authenticatedが設定されていることからもわかるように、SASL認証をパスすると、$mynetworks以外のクライアントからメールを送信することができます。そこでsmtpd_sasl_auth_enableにyesを設定し、SASL認証を有効にします。認証はDovecotに丸投げしたいので、smtpd_sasl_typeにはdovecotを指定 ((利用できるSASLプラグインの種類はpostconf -aコマンドで確認できます。)) します。
smtpd_sasl_pathには認証クライアントとしてprivate/authを指定します。これはDovecotが作成するsocket(この後で設定します)で、$queue_directory ((デフォルト値は/var/spool/postfix)) からの相対パスで指定します。ついでにメールボックスにはMaildir形式を使いたいので、home_mailboxはMaildir/としておきましょう ((submissionポートを開くだとか、SSL/TLSの使用を強制するだとか、SSLv3を禁止するだとか、そういった話は例によって省略します。)) 。

diff --git a/postfix/main.cf b/postfix/main.cf
index 5d39fc4..70e7a7e 100644
--- a/postfix/main.cf
+++ b/postfix/main.cf
@@ -39,3 +39,7 @@ mailbox_size_limit = 0
 recipient_delimiter = +
 inet_interfaces = all
 inet_protocols = all
+smtpd_sasl_auth_enable = yes
+smtpd_sasl_type = dovecot
+smtpd_sasl_path = private/auth
+home_mailbox = Maildir/

続いてDovecotの設定です。PostfixでメールボックスをMaildirにしたので、/etc/dovecont/conf.d/10-mail.conf内のmail_locationも変更します。

diff --git a/dovecot/conf.d/10-mail.conf b/dovecot/conf.d/10-mail.conf
index e78c239..3284431 100644
--- a/dovecot/conf.d/10-mail.conf
+++ b/dovecot/conf.d/10-mail.conf
@@ -27,7 +27,7 @@
 #
 # <doc/wiki/MailLocation.txt>
 #
-mail_location = mbox:~/mail:INBOX=/var/mail/%u
+mail_location = maildir:~/Maildir

次はPostfixが認証に使うソケットを作成します。これは/etc/dovecont/conf.d/10-master.conf内で設定します。最初からコメントアウトされた状態でsmtp-authの設定が存在しますので、コメントを解除しつつ、userとgroupをpostfixに設定しましょう。パーミッションを666にしておく意味は特にないため、modeも660に変更します ((そもそも/var/spool/postfix/private自体がpostfix:rootで700になっているため、変更しなくても構わないんですけどね。)) 。これでDovecotを再起動すれば、/var/spool/postfix/private/authというソケットが生成されます。

diff --git a/dovecot/conf.d/10-master.conf b/dovecot/conf.d/10-master.conf
index e3d6260..5068100 100644
--- a/dovecot/conf.d/10-master.conf
+++ b/dovecot/conf.d/10-master.conf
@@ -93,9 +93,11 @@ service auth {
   }
   # Postfix smtp-auth
-  #unix_listener /var/spool/postfix/private/auth {
-  #  mode = 0666
-  #}
+  unix_listener /var/spool/postfix/private/auth {
+    mode = 0660
+    user = postfix
+    group = postfix
+  }

これで外部からメールを送受信をする準備が整いました。Postfixを再起動したら、手元のメーラーから確認してみましょう。

dovecot-sieveのインストール

Postfixはlocal(8)によってメールをローカル配送しますが、このlocal配送エージェントは、mailbox_commandに指定された外部プログラムに配送を委任することができます。そこでdovecot-coreパッケージに含まれるdovecot-ldaにローカル配送を委任し、かつここにSieveプラグインを追加することで、最終配送前にメールをフィルタリングしようというわけです。
まず/etc/postfix/main.cfに以下の設定を追記してPostfixを再起動します ((deliverはdovecot-ldaへのsymlinkになっています。)) 。

diff --git a/postfix/main.cf b/postfix/main.cf
index 70e7a7e..86e17f5 100644
--- a/postfix/main.cf
+++ b/postfix/main.cf
@@ -43,3 +43,4 @@ smtpd_sasl_auth_enable = yes
 smtpd_sasl_type = dovecot
 smtpd_sasl_path = private/auth
 home_mailbox = Maildir/
+mailbox_command = /usr/lib/dovecot/deliver -f "$SENDER" -a "$RECIPIENT"

dovecot-sieveパッケージをインストールします。/etc/dovecot/conf.d/90-sieve.confという設定ファイルが追加されていますので、プラグインの設定を変更したい場合はこのファイルを編集します。といっても、通常はデフォルトの状態で問題ありません。強いて上げるなら、ユーザー個別のSieveスクリプト(~/.dovecot.sieve)が存在しなかった場合にのみ実行されるデフォルトスクリプト(sieve_default)を指定するくらいでしょう。sieve_defaultはコメントアウトされた状態になっているため、必要であればコメントを解除してください。

$ sudo apt-get install dovecot-sieve

LDAに関する設定は/etc/dovecot/conf.d/15-lda.confで行います。Sieveプラグインを追加したいので、mail_pluginsにsieveを追加します。

diff --git a/dovecot/conf.d/15-lda.conf b/dovecot/conf.d/15-lda.conf
index bcee86c..c67cfd6 100644
--- a/dovecot/conf.d/15-lda.conf
+++ b/dovecot/conf.d/15-lda.conf
@@ -44,5 +44,5 @@
 protocol lda {
   # Space separated list of plugins to load (default is global mail_plugins).
-  #mail_plugins = $mail_plugins
+  mail_plugins = $mail_plugins sieve
}

設定は以上です。Dovecotを再起動してみましょう。

Sieveでフィルタリングルールを書いてみる

Sieveのフィルタリングルールは「コントロールコマンド」「テストコマンド」「アクションコマンド」で構成される、非常に単純な構造をしています。コントロールには「if〜elsif〜else」「require」「stop」の三種類しかありません。実質、(必要であれば)スクリプトの先頭で外部アクションをrequireし、あとはifで条件分岐をひたすら書いていく、というスタイルになります。
たとえば次の例では、メールの宛先に指定されたメールアドレスのローカルパートが「mizuno_as」と一致した場合、example.comへメールを転送します。特定のサーバーからのアラートのみモバイルに転送する、といった使い方も簡単そうですね。

if address :localpart :is "To" "mizuno_as"
{
  redirect "mizuno_as@example.com";
}

テストコマンドにはaddressの他、メールヘッダを評価するheader、メールのサイズを評価するsize、エンベロープアドレスを評価するenvelope、要素が存在するかを評価するexists、テストの論理演算を行うallof、anyof、not、常に真/偽を返すtrue、falseがあります。マッチタイプには完全一致のis、部分一致のcontains、ワイルドカードが使用できるmatchesがあます。詳しくはRFCを参照してください。

ManageSirveでスクリプトを管理する

このように便利なSieveですが、サーバーにSSH接続してviでゴリゴリとスクリプトを書いたり、あるいはSCPやFTPでファイルをアップロードするのも面倒ですよね ((そもそも一般ユーザーにSSHは開放したくないですし、今時FTPというのも……ねえ。)) 。そんな問題を解決してくれるのがManageSieveです。ManageSieveはユーザーごとのスクリプトコレクションを管理し、有効/無効を簡単に切り替えられるようにするサービスです。またそれだけなく、アップロードされたスクリプトの文法チェックとコンパイルも自動で行ってくれます。
dovecot-managesievedパッケージをインストールしてから、Dovecotを再起動してください。DovecotがTCP:4190をListenしはじめます。

$ sudo apt-get install dovecot-managesieved
$ sudo service dovecot restart

ThunderbirdのSieveアドオンから、スクリプトを作成してアップロードしてみましょう ((現在Mozilla Add-onsから入手できるSieve 0.2.2は、Thunderbird 24以降では動作しないという問題があります。Nightly Buildの0.2.3を使うことでこの問題を回避できます。)) 。アドオンをインストールするとメニューの「ツール」以下に「Sieve Message Filters」と「Sieve Filter Settings」が追加されます。まずは〜Settingsを開き、このアカウントでSeiveスクリプトの管理を有効にしてください。ManageSieveへのログインは、デフォルトでIMAPアカウントとSSLを利用するようになっているため、特に設定変更は必要ありません。
Sieve Message Filtersを実行すると、「Server Filters」というタブが開き、サーバー上にあるフィルタースクリプトの一覧が表示されます。最初はスクリプトが存在しませんので、「New」をクリックしてスクリプトエディタを起動します。ここにSieveスクリプトを記述していきましょう。リファレンスマニュアルとリアルタイムな構文チェッカーがあるため、普通のテキストエディタよりもプログラミングしやすいでしょう。編集が終了したら「Save」ボタンをクリックします。

保存したスクリプトはサーバーの~/sieveディレクトリ内に保存されています。実際にLDAに使用されるスクリプトは~/.dovecot.sieveですので、この名前でスクリプトの実体へのシンボリックリンクを作成しなければなりません ((/etc/dovecot/conf.d/90-sieve.confの中のコメントを見るとよくわかります。)) 。これがスクリプトのActivateです。Sieve Filtersタブで有効にしたいスクリプトを選択し、Activateボタンをクリックしてください ((つまり複数のスクリプトをアップロードしておけるものの、同時にアクティブにできるスクリプトはひとつだけなことに気をつけてください。)) 。

おわりに

このように、Ubuntuであればいくつかのパッケージをインストールするだけで、お手軽にサーバーサイドでのフィルタリングが行なえます。大量のメールの山に埋もれてしまっている人や、メーラーでがんばってフィルタルールを山ほど書いているような人は、Sieveを使ってみてもよいのではないでしょうか。スパムメールを効率よく抹殺するのにも役立つかもしれませんね!

ブログ記事検索

このブログについて

このブログは、札幌市・仙台市の「株式会社インフィニットループ」が運営する技術ブログです。 お仕事で使えるITネタを社員たちが発信します!