Kompira

Menu Menu

Enterprise Technical information

外部との連携 アラートメールをフィルタリングして転送する

Unix/Linux系OSではシステムのセルフチェックを行い、結果を管理者にメールで通知するといった仕組みが動いています。また、システム管理ツールがサーバ監視を行い、異常時にはアラートメールを送信するように設定しているケースも多くあります。しかし、管理しているサーバー数が多いとメールの数も膨大となり、すべてに目を通す事は現実的ではありません。そのため、受信したメールのうち警告の通知だけを読みたい、もしくは障害通知だけ受け取れればよいといった要望があります。

今回は、受信したメールのうち差出人やタイトルが一定のパターンに一致するものをフィルタリングし、転送するジョブフローを作成します。


 

動作確認環境

ソフトウェア バージョン
Kompira 1.4.10.post10
LinuxOS CentOS6.10

または

ソフトウェア バージョン
Kompira 1.5.5.post7
LinuxOS CentOS7.8.2003

 


 

メール転送の設定

ここでは、メールサーバーよりIMAP4/POP3プロトコルを通じて、メールを取り込む「メールチャネル」を利用します。取得の際、メールはサーバーから削除されます。またKompiraのメールチャネルがチェックできるアカウントは1つであるため、メールサーバーにKompira用のメールアカウントを作成し、そのアカウントにメールが転送されるように設定を行ってください。

 

メールチャネルの設定

まず、メール受信を行うためのメールチャネルを作成します。
先程設定した転送先のメールアドレス宛のメールを受信する、 ”メール受信チャネル”という名前のメールチャネルを作成します。メールチャネルの詳細については、「メール受信をトリガーにしてジョブフローを実行する」にて紹介しております。

 

メールを処理するジョブフローの作成

ここでは
(1)メールアドレスを抽出するジョブフロー
(2)メールを転送するジョブフロー
(3)メールサーバーから受信し、他のジョブフローを呼び出すジョブフロー
の3つを作成します。

 

(1) メールアドレスを抽出するジョブフロー

メールアドレスの形式としては “taro@example.jp” といったアドレスだけを記載したものと、 “コンピラ太郎 <taro@example.jp>”のようにアカウントの名前が併記されているものがあります。アカウント名が併記されている場合にはFrom行からアドレス以外の項目を除外します。

次のジョブフローを「アドレス抽出」という名前で作成します。

 

| s = "Mail to Kompira<kompira@example.jp>" |
 
[dict = pattern('.*<([^>]+)>', typ="r").match(s)] -> # 正規表現によるマッチ
{if dict == false |
  then: 
    print(s) -> 
    [addr = s]              # アドレスが単独で記載されたケース
  else: 
    print(dict.groups[0]) -> 
    [addr = dict.groups[0]] # < > 付きでアドレスが記載されたケース
} ->
return(addr)

 

3行目では、正規表現を用いて< >で囲まれた部分をメールアドレスとして取り出すためのパターンを記述しています。パターン型データのメソッド match( ) は、 文字列と正規表現がマッチすればその情報を辞書型にして返し、マッチしなければfalseを返します。ここでは< >で囲まれていなかった場合は全文を、囲まれていた場合はその中身を取得しています。

 

(2) メールを転送するジョブフロー

メールの転送は mailto()関数を使って行います。詳細については「メールを送信する」を参照してください。メールが平文の場合はmailto()関数でそのまま送信することができますが、メッセージがHTML形式ものなど追加の処理が必要になる場合があります。

最初に、受信メールを扱いやすくするためにmail_parse()関数を用いて辞書型データに変換します。本文の内容はキーワード”Body”で取得できます。メールが平文の場合(Content-Typeが”text/plain;”の場合)は

 

{
 'Body': u'disk usage: 100%\r\n',
 'Is_Multipart': False,
 'Content-Type': 'text/plain'
 ...
}

 

のようになりますが、HTML形式のメッセージと一緒に送られる場合(Content-Typeが”multipart/alternative;”の場合など)は

 

{
 'Body': [
	      {
             'Body': u'disk usage: 100%\r\n', 
             'Is-Multipart': False, 
             'Content-Type': 'text/plain'
             ...
            }, 
	      {
             'Body':'< div dir="ltr" > disk usage: 100% </div>\r\n', 
             'Is-Multipart': False, 
             'Content-Type': 'text/html'
             ...
            }
 ],
 'Is-Multipart': True,
 'Content-Type': 'multipart/alternative'
 ...
}

 

のように平文とHTMLがそれぞれ配列の要素として格納されます。 このため、Body要素で渡されたデータが文字列の場合はそのまま処理を行い、配列の場合はそれぞれの要素を抽出して処理を行います。 この処理を行うジョブフロー「メール転送」を次のように作成します。

 

| param_to |      # 転送先メールアドレス
| param_from |    # 差出人メールアドレス
| param_subject | # メールのタイトル
| param_body |    # メールの本文
 
{ if type(param_body) == "String" |
  then: 
    print("Plain Textメールです。") ->
    mailto(to = param_to, from = param_from, subject = param_subject, 
          body = param_body)
  else:
    print("HTMLを含むメールです。" ) ->
    mailto(to = param_to, from = param_from, subject = param_subject, 
          body = param_body[0].Body, html_content = param_body[1].Body)
}

 

このジョブフローではtype()関数を用いて、本文の型をチェックしています。平文の場合には”String”という文字列が返りますので、このままmailto()関数のbodyパラメータに渡します。それ以外の場合は配列と判断し、平文部分をbodyパラメータに、HTML部分をhtml_contentパラメータに渡します。

 

(3) メールサーバーから受信し、他のジョブフローを呼び出すジョブフロー

ここでは、作成したメールチャネルとジョブフローを組み合わせ、実際に転送を行うジョブフローを作成します。
条件として
(1) タイトルに”ALERT”または”WARNING”という文字列を含む
(2) 差出人が “loginaccount@system.local”である
の両方を満たす場合にメールを転送するものとします。
メールの差出人は適宜変更してください。
条件を満たさない場合には”スキップします”というメッセージを表示して次のメールを処理します。

 

|forward_addr="admin@example.jp"|  # 転送先アドレス

<./メール受信チャネル> ->
[ msg_dict = mail_parse($RESULT)] ->
 
# 送信者アドレス抽出
[./アドレス抽出: msg_dict.From] ->
[sender_addr = $RESULT] ->

# タイトル抽出
[subject = msg_dict.get_item("Subject","")]-> 

# タイトルに指定の文字列が含まれるか確認
[dict = pattern('.*(ALERT|WARNING)', typ="r").match(subject)] ->
 
# タイトルに含まれていて、送信元が一致する場合は転送
{ if dict != false and sender_addr == "loginaccount@system.local" |
  then: 
    [./メール転送: param_to = forward_addr, param_from = sender_addr, 
                  param_subject = subject, param_body = msg_dict.Body ]
  else:
    print("条件に一致しないためスキップします。: ", sender_addr, subject)
} ->
self() # ジョブフローの先頭に戻る

 

転送条件として各ヘッダーの項目や本文の内容などを用いる事が出来ます。例えば受信日時は msg_dict.Date で参照することができます。本文を処理する際にはジョブフロー「メール転送」で見てきたように、HTML形式のメッセージの扱いにご注意ください。システムから送信されるメールが対象の場合はほぼ全てが平文のメールであるため、HTMLを含むメールを無視しても問題は少ないと思われますが、処理する対象によっては重要となります。

また本文の構造が複雑な場合には、Kompiraジョブフローのパターンマッチングだけでは難しい場合があります。その場合はKompiraのライブラリ型オブジェクトを使うことで、Python言語の文字列処理関数を利用できます。ライブラリ型オブジェクトについては、「Pythonで記述された処理をKompiraから呼び出す」を参考にしてみてください。

スタートガイド

Kompiraジョブフローの基礎

ジョブフローの簡単な例

Kompiraの機能

外部との連携