特定のメールキューを検索したい

メールキューがいっぱい

どうも、やまもとやまです。
メールサーバーで大量にキューが溜まっている!困った!
とりあえず不要なやつだけ抜き出したい!
そんなことありますよね。困ったことにそれなりに良くあります。
今回はメールキューから特定条件でキューIDを取り出してみましょう。

環境

MTAにpostfixを利用したLinuxメールサーバーを想定しています。

手順

実はpostsuperコマンドのマニュアルを見るとワンライナーが書いてあったりします。
なので、簡単に解説をしつつ試してみます。

メールキューの一覧表示はご存じの通り、mailqコマンドで可能です。
さっそく実行してみます。

# mailq
-Queue ID- --Size-- ----Arrival Time---- -Sender/Recipient-------
504F23A09E3     7145 Thu Aug 11 03:06:53  MAILER-DAEMON
(delivery temporarily suspended: connect to mail.example.jp[xxx.xxx.xxx.xxx]:25: Connection refused)
                                         jpnbank@example.jp

5523A3A0A11     6594 Fri Aug 12 09:58:44  MAILER-DAEMON
(delivery temporarily suspended: connect to mail.example.com[xxx.xxx.xxx.xxx]:25: Connection refused)
                                         mmz@example.com

5E63C3A09F0     7438 Thu Aug 11 03:07:25  MAILER-DAEMON
(delivery temporarily suspended: connect to mail.example.co.jp[xxx.xxx.xxx.xxx]:25: Connection refused)
                                         jpnbank@example.co.jp

584453A09D8     6526 Wed Aug 10 15:46:50  MAILER-DAEMON
(delivery temporarily suspended: connect to mail.example.ne.jp[xxx.xxx.xxx.xxx]:25: Connection refused)
                                         mmz@example.ne.jp

515343A0603     8504 Sun Aug 14 23:57:41  info@example.com
           (connect to mail.example.jp[xxx.xxx.xxx.xxx]:25: Connection refused)
                                         ori@example.jp

5D19A3A09F1    11168 Thu Aug 11 16:34:27  MAILER-DAEMON
            (connect to mail.example.jp[xxx.xxx.xxx.xxx]:25: Connection refused)
                                         t3c@example.jp

-- 46 Kbytes in 6 Requests.

キューが少しだけ溜まっているようです。
出力結果のうち、1行目は不要なので削除してやりましょう。
tailコマンドで -n オプションを利用します(数字のみの場合は指定行数分の末尾表示ですが、+をつけると指定行目から末尾までが表示されます)。

# mailq | tail -n +2
504F23A09E3     7145 Thu Aug 11 03:06:53  MAILER-DAEMON
(delivery temporarily suspended: connect to mail.example.jp[xxx.xxx.xxx.xxx]:25: Connection refused)
                                         jpnbank@example.jp

5523A3A0A11     6594 Fri Aug 12 09:58:44  MAILER-DAEMON
(delivery temporarily suspended: connect to mail.example.com[xxx.xxx.xxx.xxx]:25: Connection refused)
                                         mmz@example.com

5E63C3A09F0     7438 Thu Aug 11 03:07:25  MAILER-DAEMON
(delivery temporarily suspended: connect to mail.example.co.jp[xxx.xxx.xxx.xxx]:25: Connection refused)
                                         jpnbank@example.co.jp

584453A09D8     6526 Wed Aug 10 15:46:50  MAILER-DAEMON
(delivery temporarily suspended: connect to mail.example.ne.jp[xxx.xxx.xxx.xxx]:25: Connection refused)
                                         mmz@example.ne.jp

515343A0603     8504 Sun Aug 14 23:57:41  info@example.com
           (connect to mail.example.jp[xxx.xxx.xxx.xxx]:25: Connection refused)
                                         ori@example.jp

5D19A3A09F1    11168 Thu Aug 11 16:34:27  MAILER-DAEMON
            (connect to mail.example.jp[xxx.xxx.xxx.xxx]:25: Connection refused)
                                         t3c@example.jp

-- 46 Kbytes in 6 Requests.
dd

1行目が消えましたね。
次に、「(」から始まる送信先サーバーの行も削除しましょう。
grepコマンドで、0個以上のスペースと「(」で始まる行を除外します。

# mailq | tail -n +2 | grep -v '^ *('
504F23A09E3     7145 Thu Aug 11 03:06:53  MAILER-DAEMON
                                         jpnbank@example.jp

5523A3A0A11     6594 Fri Aug 12 09:58:44  MAILER-DAEMON
                                         mmz@example.com

5E63C3A09F0     7438 Thu Aug 11 03:07:25  MAILER-DAEMON
                                         jpnbank@example.co.jp

584453A09D8     6526 Wed Aug 10 15:46:50  MAILER-DAEMON
                                         mmz@example.ne.jp

515343A0603     8504 Sun Aug 14 23:57:41  info@example.com
                                         ori@example.jp

5D19A3A09F1    11168 Thu Aug 11 16:34:27  MAILER-DAEMON
                                         t3c@example.jp

-- 46 Kbytes in 6 Requests.

だいぶ見やすくなりました。
ここまでくれば条件指定しての検索も簡単そうです。
awkで条件指定してみましょう。
その際、キュー一覧の2行(送信先が複数の場合は3行以上)を1レコードして検索したいので、RS変数によりレコード区切り文字に空文字を指定します。
条件としては、送信元MAILER-DAEMONとします。
7カラム目が送信元になるので、「if ($7 == "MAILER-DAEMON")」で指定できますね。

# mailq | tail -n +2 | grep -v '^ *(' | awk 'BEGIN { RS = "" }{ if ($7 == "MAILER-DAEMON") print}'
504F23A09E3     7145 Thu Aug 11 03:06:53  MAILER-DAEMON
                                         jpnbank@example.jp
5523A3A0A11     6594 Fri Aug 12 09:58:44  MAILER-DAEMON
                                         mmz@example.com
5E63C3A09F0     7438 Thu Aug 11 03:07:25  MAILER-DAEMON
                                         jpnbank@example.co.jp
584453A09D8     6526 Wed Aug 10 15:46:50  MAILER-DAEMON
                                         mmz@example.ne.jp
5D19A3A09F1    11168 Thu Aug 11 16:34:27  MAILER-DAEMON
                                         t3c@example.jp

1カラム目だけを表示させれば、キューIDが抽出できます。

# mailq | tail -n +2 | grep -v '^ *(' | awk 'BEGIN { RS = "" }{ if ($7 == "MAILER-DAEMON" ) print $1}'
504F23A09E3
5523A3A0A11
5E63C3A09F0
584453A09D8
5D19A3A09F1

これで一覧が取り出せました!
なお、今回のケースはこのままでも問題ないのですが、アクティブキューの場合は「*」が、ホールドキューの場合は「!」がついていますので、それらが含まれる場合はtrコマンドで該当の記号を除外してやることになります(tr -d '*!')。

さて、冷静に考えてみると、送信元だけであればRS変数を使った1レコードの扱いとか要らないですね。
ところが送信元、送信先の両方を指定しようするとこれが生きてきます。
送信元MAILDER-DAEMON、送信先ドメインがexample.jpのキューを条件指定してみましょう。

# mailq | tail -n +2 | grep -v '^ *(' | awk 'BEGIN { RS = "" }{ if ($7 == "MAILER-DAEMON" && $8 ~ "@example.jp$") print}'
504F23A09E3     7145 Thu Aug 11 03:06:53  MAILER-DAEMON
                                         jpnbank@example.jp
5D19A3A09F1    11168 Thu Aug 11 16:34:27  MAILER-DAEMON
                                         t3c@example.jp

無事取り出せました!
キューIDのみの場合は以下になります。
※アクティブキューとホールドキューの記号も除外しておきます

# mailq | tail -n +2 | grep -v '^ *(' | awk 'BEGIN { RS = "" }{ if ($7 == "MAILER-DAEMON" && $8 ~ "@example.jp$") print $1}' | tr -d '*!'
504F23A09E3
5D19A3A09F1

できましたね。

まとめ

特定条件でキュー一覧を検索することができました。
これで謎のメールキューが大量に発生した場合も安心です。
よくわからないワンライナーって何も考えずコピペで実行してしまいがちですが(よくない、ぜったいによくない)、紐解きながら見てみると自分で書くときの参考になります。
よく使うコマンドも知らないオプションがあったりするので、いろいろ手を動かして試してみると面白いかもしれません。
それではまた!