Sieveを使ったIMAPのメール自動振分け

古都の老兵
2025-06-18
2025-06-18

はじめに

 以前Roundcubeを使ったウェブメールを紹介しましたが、Roundcubeで設定してもサーバー側が対応していなければ振分けはしてくれませんので今回はサーバー側の設定を行ってみましょう。

一般的なメール受信の流れ

 サーバー上のMTAとしてpostfixを使っている場合、通常は以下の様に受信したメールは各プロセスに渡され処理されます。
 外部からのメールは、smtpdが受け取りcleanupでメールを検査し、From:アドレス等の追加してメールを整形た後、メールキューに入れられます。
 メールキューに入れられたメールはqmgrがメールを取出して配送するプロセスに渡されます。
 外部に転送するような場合は、smtpに渡され外部にメールを送信され、OSのローカルアカウントであればlocalでローカルアカウントのメールボックスに、仮想化されている場合はvirtualに渡され各アカウントのメールボックスに保存されます。

 通常はこれで問題ありませんが、メールを振り分ける為にqmgrで入ったメールキューをLMTP(Local Mail Transfer Protocol)でDovecotに渡し処理させます。

Dovecotの設定

 通常のPOPやIMAPだけを使っている場合は、必要なsieveが入っていませんのでパッケージを追加します。

# dnf install dovecot-pigeonhole -y

 必要なDovecotのconfigを、/etc/dovecot/local.confに設定します。

protocols = $protocols pop3 imap sieve lmtp

mail_location = maildir:~/Maildir
auth_username_format = %n

protocol lmtp {
  mail_plugins = $mail_plugins sieve
}

plugin {
  sieve = file:~/sieve;active=~/.dovecot.sieve
  sieve_global_path = /etc/dovecot/sieve/default.sieve
  sieve_dir = ~/.dovecot.sieve
}

service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
  }
}

service managesieve-login {
    inet_listener sieve {
        address = 127.0.0.1
        port = 4190
    }
}

 設定が完了したらdovecotを再起動

# systemctl restart dovecot

Postfixの設定

 Postfixの設定についてはアカウントの管理方法によって変わりますが、ローカル配送の場合は以下の通りになります

/etc/postfix/main.cf

mailbox_transport = lmtp:unix:private/dovecot-lmtp

 正しく設定されていれば、以下の様なログになります。

Apr 29 15:12:13 sv postfix/smtpd[1136552]: 94BA7C08D5C1: client=......[xxx.xxx.xxx.xx]
Apr 29 15:12:13 sv postfix/cleanup[1136558]: 94BA7C08D5C1: message-id=<.................>
Apr 29 15:12:14 sv postfix/qmgr[988535]: 94BA7C08D5C1: from=<sample@............com>, size=46980, nrcpt=1 (queue active)
Apr 29 15:12:14 sv dovecot[988647]: lmtp(1136561): Connect from local
Apr 29 15:12:14 sv dovecot[988647]: lmtp(user)<1136561><...........>: sieve: msgid=<........................>: stored mail into mailbox 'INBOX'
Apr 29 15:12:14 sv dovecot[988647]: lmtp(1136561): Disconnect from local: Logged out (state=READY)
Apr 29 15:12:14 sv postfix/lmtp[1136560]: 94BA7C08D5C1: to=<user@sv.domain_name>, orig_to=<user@domain_name>, relay=sv.server....[private/dovecot-lmtp], delay=1.6, delays=1.5/0/0.01/0.07, dsn=2.0.0, status=sent (250 2.0.0 <user@sv.domain_name> xxxxxxxxxxxx Saved)
Apr 29 15:12:14 sv postfix/qmgr[988535]: 94BA7C08D5C1: removed

 これで振分けができるようになるのですが、動作検証していた時に1つ問題が発生しました。それは何故かフォルダー名に日本語が使われているとエラーになるのです。

fileinto action: failed to store into mailbox 'test.&MFgw,DCBMPwwiw-': Mailbox doesn't exist: test.&MFgw,DCBMPwwiw-.

 実際には該当のフォルダは存在しているのですが、どうもうまく動いてくれず振分けされない。roundcubeのフィルター設定が記述されているファイルを確認してみると、

# rule:[test]
if header :contains "from" "gmail.com"
{
        fileinto "test.&MFgw,DCBMPwwiw-";
}

 実フォルダ名が記述されていて、一見すると問題無いように見えます。
 色々試してみましたがどうにもうまくいかないので実際にsieveのコードを確認してみたところ、何とsieve側でUTF8からUTF7に変換されているようです。つまりフィルターのルールは日本語フォルダ名そのままで記述する必要があるわけです。どうやらsieveの古いバージョンは変換していなかったので、Roudcube側で変換しなくても動作するようにUTF7にわざわざ記述していたのかもしれません。それがsieve側で変換するようになってミスマッチが起こってしまった可能性があります。
 実際、Roundcube 1.5.9 ではUTF7でフィルターのルールが記述されてれますが、1.6.10だと日本語のまま保存されていました。尚、1.5.9でもRoundcube上からフィルターのルールを編集して日本語名にすれば正常に振分けされます。

最後に

 LTS版の1.5.9を使ったことで少し悩んでしまいましたが、色々勉強にもなりました。素直に最新版の1.6.10を使えば悩む必要はありませんが、インターフェイススキンがElasticしか選べないのがPCメインで使っていると少し使いづらく感じます。でもElasticはレスポンシブ対応で慣れれば問題ないでしょう。