シェルスクリプトでメールを送信する
このブログを運用している Linux サーバの監視スクリプトを作成した記事を書きました。
このスクリプトは負荷が閾値を超えた場合に警告メールを送信するようにしていて、メール送信には mail
コマンドを使ってます。
この mail
、初めて使ってみたので動作確認してみました。
動作確認を進めるなかで mail
のようにメール送信できる mutt
コマンドも触ったので、これらの検証内容をメモしておきます。
photo credit: dreams & pancakes via photopin cc
目次
- 1. パターン1:件名あり・本文なし・添付ファイルなしでメールを送信する
- 2. パターン2:件名あり・本文あり・添付ファイルなしでメールを送信する
- 3. パターン3:件名あり・本文なし・添付ファイルありでメールを送信する
- 4. パターン4:件名あり・本文あり・添付ファイルありでメールを送信する
- 5. まとめ
- 6. その他 Linux に関する記事
1. パターン1:件名あり・本文なし・添付ファイルなしでメールを送信する
上の記事で書いた監視スクリプトが送信する警告メールは、件名だけのメールにしています。
「ちょっと気にかけたほうがいいかも」ってことが分かればいいので、シンプルに件名だけにしました。
件名あり・本文なし・添付ファイルなしでメールを送信するには、-s オプションで件名を指定し、メールアドレスを引数に渡して mail
を実行します。
本文なしの場合でも空白文字を echo
とかのコマンドで mail
に渡さないと処理が止まってしまう(本文が入力されるのを待ってしまう)仕様になっているようです。
サンプルコードはこんな感じです。
#!/bin/sh PROJECT_NAME=`dirname $0 | sed -e 's#\(.*\)\/\(.*\)#\2#g'` if [ ${PROJECT_NAME} = '.' ]; then # スクリプトが置かれているディレクトリで実行した場合は pwd を使う PROJECT_NAME=`pwd | sed -e 's#\(.*\)\/\(.*\)#\2#g'` fi SCRIPT_NAME=`basename $0` MAIL_ADDRESS=mail@addr.ess SUBJECT="[${PROJECT_NAME}]${SCRIPT_NAME}" BODY= echo ${BODY} | mail -s ${SUBJECT} ${MAIL_ADDRESS}
件名にはプロジェクト名と実行スクリプト名を入れています。
2. パターン2:件名あり・本文あり・添付ファイルなしでメールを送信する
次に本文ありのパターンです。
これはパターン1とほぼ同じです。
違いは mail
に渡す文字が空白文字ではなくなったところだけです。
サンプルコードはこんな感じです。
#!/bin/sh PROJECT_NAME=`dirname $0 | sed -e 's#\(.*\)\/\(.*\)#\2#g'` if [ ${PROJECT_NAME} = '.' ]; then # スクリプトが置かれているディレクトリで実行した場合は pwd を使う PROJECT_NAME=`pwd | sed -e 's#\(.*\)\/\(.*\)#\2#g'` fi SCRIPT_NAME=`basename $0` MAIL_ADDRESS=mail@addr.ess SUBJECT="[${PROJECT_NAME}]${SCRIPT_NAME}" BODY="メール本文をここに書く" echo ${BODY} | mail -s ${SUBJECT} ${MAIL_ADDRESS}
3. パターン3:件名あり・本文なし・添付ファイルありでメールを送信する
本文はないけど添付ファイルはありというパターンです。
mail
を使って本文あり・添付ファイルありで送信できるんじゃないかと試行錯誤しましたが、うまくできませんでした。なので、本文なし・添付ファイルありになっています(別のコマンドを使って本文あり・添付ファイルありで送信できたので、それは次で紹介します)。
で、mail
はテキストを送信するように実装されているので、 mail
単体では添付ファイルは扱えないみたいです。参照元を引用しておきます。
mailはテキストを特定の書式で送るのが原理のため
そこで、uuencode
を使って添付ファイルをエンコードして送信する、という方法を取るのが一般的なようです。これも参照元から引用しておきます。
uuencodeは、バイナリデータをテキストデータに変換するUNIX及びUnix系OSのコマンド。或いは、それによって生成されるテキストデータのフォーマット。
環境に uuencode
がインストールされているかは which
で確認できます。
インストールされていないと次のように表示されます。
$ which uuencode uuencode not found
uuencode
を yum
でインストールします。uuencode
は sharutils パッケージに含まれているようです。
$ sudo yum -y install sharutils : : $ which uuencode /usr/bin/uuencode
uuencode
を使ったサンプルコードはこんな感じです。
添付ファイルを引数で指定するようにしてみました。
#!/bin/sh SCRIPT_NAME=`basename $0` if [ $# -ne 1 ];then # スクリプトの第一引数に添付ファイルのパスを指定してもらう echo "Usage: ${SCRIPT_NAME} attachment_file_path" 1>&2 exit 1 fi ATTACHMENT_FILE_PATH=$1 ATTACHMENT_FILE=`basename ${ATTACHMENT_FILE_PATH}` PROJECT_NAME=`dirname $0 | sed -e 's#\(.*\)\/\(.*\)#\2#g'` if [ ${PROJECT_NAME} = '.' ]; then # スクリプトが置かれているディレクトリで実行した場合は pwd を使う PROJECT_NAME=`pwd | sed -e 's#\(.*\)\/\(.*\)#\2#g'` fi MAIL_ADDRESS=mail@addr.ess SUBJECT="[${PROJECT_NAME}]${SCRIPT_NAME}" uuencode ${ATTACHMENT_FILE_PATH} ${ATTACHMENT_FILE} | mail -s ${SUBJECT} ${MAIL_ADDRESS}
4. パターン4:件名あり・本文あり・添付ファイルありでメールを送信する
最後に本文あり・添付ファイルありのパターンです。
いろいろ調べてみると、mail
ではなく mutt
というコマンドを使うとできるようです(mutt というのは、”Mutt Mail User Agent” の略称のようです)。
さっそく環境に mutt
をインストールします。
インストールには uuencode
と同様に yum
を使います。
$ which mutt mutt not found $ sudo yum -y install mutt : : $ which mutt /usr/bin/mutt
ちなみにインストールした mutt
のバージョンは次の通りでした。
$ mutt -v Mutt 1.5.20 (2009-12-10)
で、mutt
を使った件名あり・本文あり・添付ファイルありでメールを送信するサンプルコードはこんな感じです。
添付ファイルは引数で指定します。
#!/bin/sh SCRIPT_NAME=`basename $0` if [ $# -ne 1 ];then # スクリプトの第一引数に添付ファイルのパスを指定してもらう echo "Usage: ${SCRIPT_NAME} attachment_file_path" 1>&2 exit 1 fi ATTACHMENT_FILE_PATH=$1 PROJECT_NAME=`dirname $0 | sed -e 's#\(.*\)\/\(.*\)#\2#g'` if [ ${PROJECT_NAME} = '.' ]; then # スクリプトが置かれているディレクトリで実行した場合は pwd を使う PROJECT_NAME=`pwd | sed -e 's#\(.*\)\/\(.*\)#\2#g'` fi MAIL_ADDRESS=mail@add.ress SUBJECT="[${PROJECT_NAME}]${SCRIPT_NAME}" BODY="ここに本文を書く" echo ${BODY} | mutt -s ${SUBJECT} -a ${ATTACHMENT_FILE_PATH} -- ${MAIL_ADDRESS}
このスクリプトを作成するにあたって、関係ありそうな部分を man
でざっとさらってみたのでメモしておきます。
- 本文の指定は
mail
と同じ - 件名も
mail
と同じく -s オプションで指定する - 添付ファイルの指定は -a オプションを使う
- -a オプションは、オプションの一番最後に指定する
- -a オプションを使う場合、メールアドレスとの区切りには “–” を指定する
5. まとめ
以上、mail
と mutt
コマンドを使った基本的なメール送信パターンの紹介でした。
連絡手段は多様化していますが、業務ではメール連絡がまだまだ一般的なので「こんなことができる」ってことをさらりと知っておくいいかもしれないですね。
- 件名指定には -s オプション
- 本文は
echo
などを使ってコマンドに渡す - ファイル添付は、、、
mail
ならuuencode
でエンコードするmutt
ならmutt
単体で送信できる
- 本文あり、かつ、添付ファイル付きのメールを送信する場合は
mutt
を使う
6. その他 Linux に関する記事
その他の Linux に関する記事は次の通りです。
気になる記事があったらぜひチェックしてみてください!
-
”Jerseyの@PathParamはスラッシュの間に複数指定できる”VagrantのBoxファイルをカスタマイズして独自のBoxファイルを作成する”バリデーションチェックにJava8のOptionalを使ってスマートに書く(自分比)”ユニットテストの偏りを防ぐ命名規則の付け方”Vagrantで起動したCentOS上のOctopressをホストOSから確認する設定”Vagrantで起動したCentOS上のMySQLにホストOSからログインする設定”Optionalから値を取り出すにはorElseGet()を使う”GoogleGuavaのRangeを使って範囲判定を簡潔に書く”Functions#compose() を使って Function を合成するサンプル(Java8 との比較付き)”Google Guava の Function を使った文字列加工の FluentIterable サンプル”Gradle で Java アプリのプロジェクトを作成して Eclipse にインポートするまでの手順”SDKMAN!(GVM) を使って Mac に Gradle をインストールする”Exec Maven Plugin で maven コマンドでアプリを起動する”Spark を使って JSON を返すシンプルな API を書いてみた”Stream#filter()で絞り込みmap()で処理するコードスニペット”Stream#map()とStream#collect()を使ってListを生成する”Optional型の変数にget()とifPresent()は使わない”Java8 の Optional 型を返す Generics を使ったメソッドを定義する”Java8 の Optional とガード節”Bundler を使ってプロジェクト用の Gem をインストールして Gemfile をバージョン管理ツールに登録するまでの流れ”シェルスクリプトでcdしたいパスにスペースが入っている場合の対処法”CentOSにRubyのBundlerをインストールして使い始める人向けの簡単なまとめ”amazon-ecsを使った検索のエラー原因を確認する”CentOS6.5にGitをソースコードからインストールする”CentOSのバージョン6.5(64ビット)にamazon-ecsをインストールする”CentOSのバージョン6.5(64ビット)にRuby2.1.2をインストールする”mp3splt を実行して "undefined symbol: mp3splt_u_check_if_directory" と出力されたときの対処法”検証用の CentOS をインストールした直後に行う初期設定手順”64ビット版のCentOSをVMwareにインストールできない場合の対処法”参照可能な yum リポジトリを確認する yum コマンドとワンライナー”yum のリポジトリ ATrpms を参照できるように設定する”scp を使ってファイルのコピーを実行したら "command not found" と表示されたときの対処法”scp コマンドを yum を使って CentOS にインストールする”yum が参照するミラーサイトの baseurl を変更して日本国内のものに設定する”CentOS に yum-plugin-priorities プラグインをインストールする”Linuxでmp3をお手軽に結合する”ロードアベレージを監視するシェルスクリプトを作成してみた”保存ダイアログを表示させてファイルをダウンロードさせる方法”Error オブジェクトの種類と独自例外オブジェクトの作成方法”昭和記念公園で快適に過ごすために覚えておきたいこと”海の公園潮干狩りレポート 2014年版”GTMatrix の診断結果でF判定になった項目の対策まとめ”Tomcatの再起動はworkディレクトリも削除しておいた方が無難”JavaScriptなどをフォーマットするGruntプラグイン grunt-jsbeautifier を使ってみる”Eclipse がエラーメッセージを出力して起動しなくなった場合の対処法”Markdown記法のテキストに書いたソースコードをシンタックスハイライトするプラグイン”子どもの初めての習い事に水泳を選んだ理由”横浜「海の公園」の潮干狩り計画(2014)を立ててみた”GoogleMapsAPIを使って緯度・経度からMarkerを作成する方法”ブログを本格的に始めて3ヶ月経って分かったこと”GoogleMapsAPIを使ってMarkerを削除する方法”GoogleMapsAPIを使ってMarkerの表示と非表示を切り替える方法”Grunt の grunt-contrib-watch を使うと CPU 使用率が上がるので spawn: false を試してみた結果”BOSE のスピーカー Companion2 Series III の購入を検討されている方に”BootstrapValidator の基本的なバリデーションを試すサンプルを作成しました”TwitterBootstrap3 用のバリデーションチェックプラグイン BootstrapValidator の導入から Live チェックまでを試してみた”JavaScript のクラス定義”InputStream に格納されているストリームデータのサイズを取得する”Grunt + QUnit + PhantomJS でテストを自動実行してくれる環境を構築する”GoogleMaps の JavaScript API(v3) を使って、常に1つの InfoWindow だけ表示されるように制御する”GoogleMap サンプルのプロジェクトに Grunt の LiveReload を有効にする設定を追加しました”GitHub にアップされているブランチをローカルに取り込む”GoogleMaps の JavaScript API (v3) を使って地図上に複数の Marker を表示するサンプル”Sublime Text3 で JavaScript を書くために設定したプラグインとキーバインド”Sublime Text3 で Markdown のシンタックスハイライトを有効にする手順”TwitterBootstrap3 をベースにした画面に GoogleMap を埋め込む”Sublime Text3 に SublimeLinter-jshint をインストールしてみた”GoogleMap の Marker に InfoWindow を設定するサンプル”Sublime Text3 のインストール直後に行った設定メモ”GoogleMap を使って住所から緯度・経度を計算する”プロフィールページを追加しました”住所から GoogleMap を表示するサンプル”Java でファイルが1つだけ圧縮された zip を解凍するサンプル”Android アプリで ActionBar の背景色を変更する方法”Android アプリで "external/chromium/net/disk_cache/stat_hub.cc:216" とエラーメッセージが表示された場合の対処法”Android アプリで特定の Activity が呼ばれたらアプリを終了させる方法”Android の非同期処理を行う Loader の起動方法”Underscore.js の template を使うときは HTML にテンプレートを書こう”JSON をオブジェクトに変換するときに注意したいこと”Android アプリ開発で "cannot perform this action inside of onloadfinished" とエラーメッセージが表示された場面の対処法”Android アプリ開発で "Unable to resolve target 'android-16'" などとエラーメッセージが表示された場合の対処法”第24節 ミランvsボローニャ に関する記事ふりかえり”Daft Punk 素人がヘビーローテーションしている YouTube 動画10選”One Direction - "Story of My Life"”Underscore.js の template を使ってドリルダウンを実装するスニペット”jQuery を使って表示する画像を setInterval を使って切り替える”jQuery を使ってページの opacity を徐々に上げて fadeIn して見せる”Underscore.js の template と each を使って JSON から select タグを生成する”Stinger3 に Pocket ボタンを設置しました”Stinger3 に Feedly ボタンを設置しました”Stinger3 の single.php で使われている style.css をカスタマイズ”jQuery を使ってタグに設定されているクラスをすべて取り除いた後に指定のクラスに変更する”opencsv の HeaderColumnNameTranslateMappingStrategy を使って CSV を Bean に変換する”opencsv の HeaderColumnNameMappingStrategy を使って CSV を Bean に変換する”opencsv の ColumnPositionMappingStrategy を使って CSV を Bean に変換する”spring framework を使ったデスクトップアプリ(standalone app)で context から getBean でオブジェクトを取得する。@Autowired による紐付け”jsvc を使って daemon として起動した Tomcat のプロセス数が2つなのは正しい”Stinger3 の追尾式 SNS ボタンを削除する方法”spring framework を使ったデスクトップアプリ(standalone app)で maven-jar-plugin を使って作成した JAR を java コマンドで実行する”Tomcat7 を jsvc で起動する手順”spring framework を使ったデスクトップアプリ(standalone app)で context から getBean でオブジェクトを取得する”指定した年月の日付を Calendar オブジェクトの一覧で取得する”リストに格納されているオブジェクトを marshal する場合に付与すると便利な @XmlElementWrapper アノテーション”ClassLoader を使って getResourceAsStream で取得したファイルを UTF-8 で読み込む”JAXB を使ってオブジェクトを marshal する際に要素名を指定する方法”JAXB を使ってオブジェクトを marshal するために忘れてはいけない2つのこと”相模原市にある銀河アリーナでスケートを楽しむ”MUSH&Co. "明日も"”「領」と書かれた車のナンバープレートを見た!”Jersey で POST 送信処理後にダイレクトする方法”Android アプリでタイムゾーンを Asia/Tokyo で現在時刻を取得する”jQuery を使ってファイルアップロードフォームのファイルが選択されているかを確認する方法”jQuery を使ってチェックボックスのチェックを付けたり外したりするコードスニペット”9円!!”レスポンスにサムネイル画像を返す API のサンプル”ImageMagick を使ってサムネイル画像を作成する方法”ImageMagick を使って画像を結合する方法”ImageMagick を使って Exif を取り除く方法”Maven で作成したプロジェクトのソースコードを JAR にする方法”Spring の Scheduled アノテーションを使った cron サンプル”Spring の設定ファイル applicationContext.xml の内容をプロパティファイルに切り出す”MySQL の JDBC ドライバで設定しておきたい rewriteBatchedStatements プロパティ”SpringJDBC が発行する SQL をログに出力する”Spring の DataSource に DBCP を使用する”JUnit4 のパラメータ化テストは4通りの方法で書ける”JUnit4 の Enclosed を使ったテストクラスサンプル”JUnit4 で JavaBeans の assertThat を簡潔に書きたい”JUnit4 で List の assertThat を簡潔に書きたい”AgeFileFilter を使ったフィルタ処理のサンプル”SizeFileFilter を使ったフィルタ処理のサンプル”DirectoryFileFilter を使ったフィルタ処理のサンプル”海老名サービスエリアに徒歩で行ってきました”commons-io に見るファイル操作処理のヒント(FilenameUtils編)”Commons IO の LineIterator#isValidLine メソッドをオーバーライドしたサンプル”プロセスの起動を確認するプログラム”配列の内容をファイルに書き込む”拡張子を指定したフィルタの実装サンプル”opencsv を使って CSV ファイルの読み込み開始行を指定する”opencsvの検証をしてみた”commons-io に見るファイル操作処理のヒント(FileUtils編その2)”ファイルを読み込んでその内容を保持する”プログラミングの「面倒くせー」を減らす試み”Redcarpet を使って Markdown をパースする”commons-io に見るファイル操作処理のヒント(FileUtils編その1)”commons-io に見るファイル操作処理のヒント(IOUtils編)”commons-io に見るファイル操作処理のヒント(FileBasedTestCase編)”SQL で表現する階層関係のモデル”Github に人間認定されなくなった”ビジネスメールの言い回しテンプレート”こどもの国の屋外プールに行ってきた”Maven で Web アプリ用のプロジェクトを作成してからコーディングを着手するまでにやること”Android アプリで Google Analytics へトラッキングするサンプルクラス”電子政府推奨暗号リスト”より安全にパスワードを保存するために考えること”初めてのアンドロイドアプリ開発振り返り”ローカルブランチの確認と切り替え方法”ファイルに関するユーティリティ”ディレクトリに関するユーティリティ”WebView からデフォルトブラウザを開く”位置情報取得に関する覚え書き、その2”AlertDialog の背景をタップできなくする”位置情報取得に関する覚え書き”AlertDialog がキャンセルされたときに処理を行うスニペット”with_index メソッド”ImageMagick を使って画像の縦横サイズを縮小する”ファイルの拡張子が JPG であるかを問い合わせるスニペット”画像ファイルを選別するFilenameFilter”画像ファイルのサイズ(縦横じゃなくて容量)を取得するスニペット”サーブレットでクラスパス上にあるプロパティファイルを参照するスニペット”Jetty でシンプルなプロジェクトを作成してみた”google-gson でシリアライズ・デシリアライズしたサンプル”Java から VBScript を使って Excel を印刷する”IE9 のキャッシュ対策”今年も潮干狩りに行ってきた”amazon-ecs を使って Amazon から関連商品情報を取得するサンプル”no space left と表示されたときの対処法”amazon-ecs を使って Amazon から商品情報を取得するサンプル”CVS でタグ間で変更があったファイルを抽出するスクリプト”VPS に Redmine を設置したときに対処したトラブル”VPS に Nokogiri をインストールしたときのトラブル
Googleアドセンス用(PC)
関連記事
-
-
GoogleGuavaのRangeを使って範囲判定を簡潔に書く
次のような判定処理を if 文で書くことがよくある。 もし 100 よりも大きければ(=大小判定
-
-
yum のリポジトリ ATrpms を参照できるように設定する
あるツールの動作検証をしようと調べたところ、そのツールは ATrpms リポジトリが提供しているとの
-
-
Vagrantで起動したCentOS上のOctopressをホストOSから確認する設定
タイトルの通りだが、Vagrant を使って起動した CentOS に Octopress をインス
-
-
参照可能な yum リポジトリを確認する yum コマンドとワンライナー
あるパッケージをインストールするために配布リポジトリの設定を追加することがあります。 ビジネスユー
-
-
Sublime Text3 のインストール直後に行った設定メモ
突発的に自宅のマシンにインストールしてあった Sublime Text2 を 3 にアップデートしま
-
-
Eclipse がエラーメッセージを出力して起動しなくなった場合の対処法
Eclipse の exe ファイルをクリックすると(または、実行すると)、 Eclipse のスプ
-
-
VPS に Redmine を設置したときに対処したトラブル
Redmine のインストール自体は Redmine 2.3をCentOS 6.4にインストールする
-
-
Linuxでmp3をお手軽に結合する
このブログを運用している Linux サーバで radiko.jp から番組を mp3 に録音して個
-
-
ロードアベレージを監視するシェルスクリプトを作成してみた
このブログを運用している Linux サーバの負荷が高い状態になってました。 何か被害にあったとかで
-
-
CentOS6.5にGitをソースコードからインストールする
CentOS 6.5 の64ビット版を "Minimal" でインストールした環境で、git sta