BLOG ベアメールブログ
2024.10.24 (木)
HowToガイドシェルスクリプト+msmtpでメールを送信する方法
メルマガ送信システムや、申し込みフォームからの自動返信メール、ECサイトであれば購入確認や発送を知らせるトランザクションメールなど、さまざまな環境からメールは送られています。そのシステムのバックグラウンドで動いているのはメールサーバと、メールサーバに指示を出すためのプログラムです。
メールを送信するにはインターネット上にある他サーバと通信することになるため、メール送信にはSMTPサーバ(メールサーバ)が必要となり、プログラム言語単体でメールを送信できる言語はありません。しかし、多くのプログラム言語では、バッグエンドにあるメールサーバと接続しやすくするためのライブラリやモジュールといった仕組みが提供されています。
このシリーズでは、色々なプログラムでメールを送ってみたいと思います。 今回は第1回として、シェルスクリプトとmsmtpでメールを送る方法を紹介します。
目次
環境情報
本記事では、メールサーバとは別のサーバでプログラムを実行します。
メールサーバに接続可能でプログラムが実行できる環境であれば、クライアントPCやメールサーバと同一環境でも問題ありません。
プログラムを実行可能なサーバやクライアントPC
実行環境のOSは「AlmaLinux 8.10」を使用しています。
# cat /etc/redhat-release
AlmaLinux release 8.10 (Cerulean Leopard)
メールサーバ
OSは「AlmaLinux 8.9」、SMTPサーバとして「postfix 3.5.8」を使用しています。
# cat /etc/redhat-release
AlmaLinux release 8.9 (Midnight Oncilla)
# postconf | grep mail_version
mail_version = 3.5.8
milter_macro_v = $mail_name $mail_version
プログラムの実行環境とメールサーバ間は587ポートで接続し、SMTP AUTHで認証します。
シンプルですが今回の構成を図にするとこんな感じです。
シェルでメールを送ってみる
最初はLinuxでおなじみのUnixシェルを使ってメールを送信したいと思います。
シェルとはユーザとコンピュータを繋ぐプログラムです。Linux系であれば標準で導入されていますので、一番試しやすいのではないでしょうか。
シェルにはzshやtcshなど様々な種類がありますが、今回使うのはAlmaLinux標準の「bash」を使用します。
bashでメールを送信する場合の選択肢
「bash」には他言語でいうところのモジュールシステムが組み込まれていません。また、一般的に公開されているライブラリにもメールに関するものでメジャーなものはありません。(私が把握している限り)
しかし、シェルスクリプトはコマンド等をインストールすることで機能を拡張することが可能です。
シェルを使ってメールを送る方法としては、telnetコマンドやopensshコマンドを利用してメールサーバと対話しながら送信する方法がメジャーですが、telnetやopensshはコンソールから操作がしやすい反面、スクリプト内で使用するとなると、対話中にどうやって文字を入力させるのか、という課題があります。
そこで、以下のようなコマンドが候補となります。
mailコマンド
mail コマンドは、簡単なメール送信に適しています。
- メリット:簡単で軽量、広くサポート、スクリプトとの連携が容易
- デメリット:外部SMTP認証のサポートが不十分
sendmailコマンド
通常デフォルトでインストールされている postfix パッケージに同梱されている Sendmail 互換インターフェースの sendmail コマンドを使用します。より高度なメール送信が可能。
- メリット:強力で柔軟なMTA、Postfixが入っていれば使える
- デメリット:設定が複雑、軽量なツールと比べて重い
muttコマンド
mutt はCLIベースのメールクライアントで、SMTPサーバーを使ったメール送信が可能です。
- メリット:豊富な機能、外部SMTPに対応
- デメリット:設定がやや難しい
msmtpコマンド
msmtp は外部のSMTPサーバーを利用してメールを送信するためのシンプルなツールです。
- メリット:軽量でシンプル、外部SMTPに対応、ロギングも簡単。プラグインシステムにより、機能を拡張することが可能
- デメリット:キュー管理がない、高度な機能は少ない
シェルスクリプト+msmtpコマンドで送信する方法
今回は「メールサーバにSMTP接続してメールを送る」というスクリプトをbashで作成し、メール送信にmsmtpコマンドを使用します。
msmtpは前述の通り高度な機能はないものの、シンプルで軽量、柔軟性が高いという特徴を持つSMTPクライアントなので、簡単な設定で使い始めることができます。しかし、MTA(Mail Transfer Agent)としての機能はないため、MTA機能が必要であればsendmail等のMTA機能を持つソフトウェアの導入を検討する必要があります。
本スクリプトを作成するにあたり、必要なものは下記のとおりです。
bash
bashのバージョンは「4.4.20」になります。
# bash --version
GNU bash, バージョン 4.4.20(1)-release (x86_64-redhat-linux-gnu)
msmtpコマンド
msmtpコマンドがインストールされていない場合は、EPELレポジトリからインストール可能です。
msmtpの設定
まずは、接続先のSMTPサーバの接続情報をmsmtpの設定ファイルに記載します。
本記事ではホームディレクトリ配下に「.msmtprc」というファイルを作成しました。
例えば、rootユーザの場合は下記のようになります。
# vi /root/.msmtprc
設定ファイルにSMTPサーバへの接続情報を追加します。
※実際の環境に合わせて値を置き換えて下さい。
defaults
auth login #smtp auth で認証
tls off # TLS使用有無設定。使用する場合はon
account smtp #設定ファイル内の識別子(任意の文字)
host "SMTP_HOST" #SMTPホスト名
port 587 #接続するポート番号
user "FROM_ADDRESS" #認証ユーザ
password "YOUR_PASSWORD" #パスワード
account default : smtp #デフォルトで使用するaccount識別子
シェルスクリプトの作成
次に任意のディレクトリでスクリプトを作成します。
本記事ではシェルスクリプトを「send_mail.sh」という名前で作成します。
# vi send_mail.sh
「send_mail.sh」に下記の内容を貼り付け、保存します。
#!/bin/bash
TO=$1
SUBJECT=$2
BODY=$3
ENVELOPE_FROM="ENVELOPE_FROM_ADD" #エンベロープFROMアドレス
HEADER_FROM="HeaderFrom Name <HEADER_FROM_ADD>" #ヘッダFROMアドレス
# Send mail using msmtp
(
echo "From: $HEADER_FROM"
echo "To: $TO"
echo "Subject: $SUBJECT"
echo "Content-Type: text/plain; charset=UTF-8"
echo ""
echo "$BODY"
) | msmtp --from="$ENVELOPE_FROM" -t
デバッグモードで実行
保存ができたら実行してみましょう
このスクリプトでは引数を3つ使うので、下記のような形でスクリプト名の後ろに「Toアドレス」、「件名」、「メール本文」の順番に任意の値を追加します。
send_mail.sh "xxxxxxx@xxx.xxx" "Test Mail from Shell Script" " Message From Shell Script"
スクリプト本体を直接実行する方法もありますが、今回は動きを確認するために「bash」コマンドに「-x」オプションを付けてデバッグモードで実行します。これにより変数の代入など、スクリプトの動きが分かりやすくなります。
bash –x send_mail.sh "xxxxxxx@xxx.xxx" "Test Mail from Shell Script" "Message From Shell Script"
※実際に実行されることに注意して下さい。
正常に実行されると以下のようなメッセージが出力されます。
+ TO=TO_ADDRESS
+ SUBJECT='Test Mail from Shell Script'
+ BODY='Message From Shell Script'
+ ENVELOPE_FROM=ENVELOPE_FROM_ADDRESS
+ HEADER_FROM='headerfrom Name <headerfrom@xxxxxx.com>'
+ echo 'From: headerfrom Name <headerfrom@xxxxxx.com>'
+ echo 'To: TO_ADDRESS'
+ echo 'Subject: Test Mail from Shell Script'
+ echo 'Content-Type: text/plain; charset=UTF-8'
+ echo ''
+ echo 'Message From Shell Script'
+ msmtp --from=ENVELOPE_FROM_ADDRESS –t
エラーは出ていないようですね。
メールボックスを確認すると、テストメールが届いていました。
From欄に指定したヘッダFROMが記載されていることが確認できます。
注意事項
今回作成したプログラムではSMTP接続に失敗した場合でもリトライされません。
また、エラー処理も最低限となっておりますので、実際に業務やサービスとして使用される場合は、SMTP接続に失敗した場合のリトライ処理、プログラムの再実行処理、エラー処理やログの生成などのカスタマイズが必要になります。
具体的な利用例
最後に、作成したスクリプトの活用例についていくつか紹介します。
サーバーの監視
簡易的なサーバー監視として、CPU使用率、メモリ消費量、ディスク容量などを定期的にチェックし、問題が発生した場合にメールで通知するために使用できます。
例:CPU使用率が高すぎる場合にアラートを送信
#!/bin/bash
THRESHOLD=80
MAIL_TO="admin@example.com"
MAIL_SUBJECT="CPU使用率警告"
SEND_MAIL_SCRIPT="./send_mail.sh"
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
if (( $(echo "$CPU_USAGE > $THRESHOLD" | bc -l) )); then
MAIL_BODY="CPU使用率が$THRESHOLD%を超えています: $CPU_USAGE%"
"$SEND_MAIL_SCRIPT" "$MAIL_TO" "$MAIL_SUBJECT" "$MAIL_BODY"fi
アプリケーションのログ監視:
システムやアプリケーションのログを解析し、特定のエラーメッセージや異常な動作が検出された場合に、その内容を管理者にメールで通知します。
例:ログファイルに「ERROR」が含まれているかチェックして通知
#!/bin/bash
LOG_FILE="/path/to/logfile"
SEND_MAIL_SCRIPT="./send_mail.sh"
MAIL_TO="admin@example.com"
MAIL_SUBJECT="ログエラー通知"
if grep -q "ERROR" "$LOG_FILE"; then
MAIL_BODY=$(cat "$LOG_FILE")
"$SEND_MAIL_SCRIPT" "$MAIL_TO" "$MAIL_SUBJECT" "$MAIL_BODY"
fi
APIや外部サービスの応答チェック:
Webサービスの応答時間やステータスコードを定期的にチェックし、異常な場合には管理者に通知することもできます。
例:Webサービスのステータスコードをチェックして通知
#!/bin/bash
URL="https://example.com"
SUCCESS_STATUS=200
MAIL_TO="admin@example.com"
MAIL_SUBJECT="サービス異常通知"
SEND_MAIL_SCRIPT="./send_mail.sh"
STATUS=$(curl -o /dev/null -s -w "%{http_code}" "$URL")
if [ "$STATUS" -ne "$SUCCESS_STATUS" ]; then
MAIL_BODY="サービスに異常があります。ステータスコード: $STATUS"
"$SEND_MAIL_SCRIPT" "$MAIL_TO" "$MAIL_SUBJECT" "$MAIL_BODY"
fi
まとめ
今回は、シェルスクリプトを用いて簡単なメール送信プログラムを作成しました。シェルスクリプトは、Linux環境において非常に汎用性が高く、システム管理や自動化の分野で広く利用されています。
本記事で紹介したスクリプトは、メール送信の基礎的な部分を紹介していますが、より複雑な機能が必要な場合は、必要に応じてカスタマイズしてください。例えば、複数の宛先への送信、添付ファイルの追加、HTML形式のメール作成など、様々な拡張が可能です。
メール送信の自動化は、システム管理や業務効率化に大きく貢献しますので、その第一歩として、本記事が役立てば幸いです。