はじめに
AmazonLinuxで新しいホストを構築していると、メール送信テストなどでメールを送信しようとしたときにmailコマンドがデフォルトで使えませんでした。この際依存をsendmailコマンドだけにしてみましたので紹介します。
メールは添付ファイルの有無に関わらず、単なるテキストデータとしてやり取りされます。細かい取り決めはたくさんありますが、大まかな構造はさほど複雑ではありません。まずは構造を確認します。次に、具体的なBashプログラムを紹介します。
メールの構造
メールをテキストデータとしてみたとき、大まかには下記の3つのパートに区切る事ができます。
- 送り主、宛先、件名などが載ったヘッダーパート
- メール本文をBase64エンコードしたボディーパート
- 添付ファイルをBase64エンコードしたアタッチメントパート
このうち、アタッチメントパートは複数設けることができます。各パートは任意に設定できるバウンダリー文字列で区切ります。後程紹介するプログラム中では「SECTION」としています。早速プログラムを紹介します。
プログラム
メール件名はUTF-8を考慮した変換を加えてあります。メール本文と添付ファイルは予めファイルに書き出しておきました。メール本文の文字コードはUTF-8を想定していますが、EUC-JPでもShift-JISでも、CP932でもなんでもOKです。ただし、「Content-Type: text/plain; charset=”UTF-8″」の箇所もあわせて調整する必要があります。
添付ファイルは今回tar.gz形式のバイナリデータです。これをbase64エンコードしてテキストで表現します。他の形式のファイルを添付したい場合は、ヘッダー「Content-Type」とヘッダー「Content-Disposition: attachment; filename=\”archive-${DATE}.tar.gz\”」を適切に変更してください。なお、このプログラムでは添付ファイルは1つだけですが、必要があれば2つ目、3つ目、とバウンダリー文字列をはさみながら増やすことができます。
添付ファイルがなく、ヘッダーパートとボディーパートだけの場合でも、「Content-Type: multipart/mixed; boundary=”SECTION”」はそのままで問題ありません。マルチパートを指定したときはバウンダリー文字列が必要になる、とだけ覚えておけば問題ないでしょう。
~/bin/send_mail_with_attachment.sh
#!/bin/sh
MAIL_TO="hostmaster <hostmaster@example.com>"
MAIL_FROM="root <root@example.com>"
SUBJECT="添付ファイル付きメール送信テスト"
DATE=$(date '+%Y%m%d')
#### Mail Message Build Process.
TMPFILE_TEXT=$(mktemp /tmp/mailpart-text-XXXXXX)
echo "Message text here. ${DATE}" > ${TMPFILE_TEXT}
#### File Archive Process.
TMPDIR_ATTACHMENTS=$(mktemp -d /tmp/mailpart-attachments-XXXXXX)
# put files to ${TMPDIR_ATTACHMENTS} here.
cp /var/log/secure ${TMPDIR_ATTACHMENTS}/secure.log
cat /proc/meminfo > ${TMPDIR_ATTACHMENTS}/meminfo.log
cd ${TMPDIR_ATTACHMENTS}
tar fcz ../archive-${DATE}.tar.gz *
cd ..
#### Mail Build Process.
TMPFILE_MAIL=$(mktemp /tmp/mail-XXXXXX)
# mail header part.
SUBJECT=$(echo -n '=?UTF-8?B?'${SUBJECT}'?=')
echo "From: ${MAIL_FROM}" > ${TMPFILE_MAIL}
echo "To: ${MAIL_TO}" >> ${TMPFILE_MAIL}
echo "Subject: ${SUBJECT}" >> ${TMPFILE_MAIL}
echo 'Content-Type: multipart/mixed; boundary="SECTION"' >> ${TMPFILE_MAIL}
echo '' >> ${TMPFILE_MAIL}
# mail body part.
CR=$(printf '\r')
echo '--SECTION' >> ${TMPFILE_MAIL}
echo 'Content-Transfer-Encoding: base64' >> ${TMPFILE_MAIL}
echo 'Content-Type: text/plain; charset="UTF-8"' >> ${TMPFILE_MAIL}
echo '' >> ${TMPFILE_MAIL}
cat ${TMPFILE_TEXT} | \
sed "/^\$/s/\$/$CR/" | \
sed "/[^$CR]\$/s/\$/$CR/" | \
base64 >> ${TMPFILE_MAIL}
# mail attachment file (tar.gz) part.
echo '--SECTION' >> ${TMPFILE_MAIL}
echo 'Content-Transfer-Encoding: base64' >> ${TMPFILE_MAIL}
echo "Content-Type: application/gzip; name=\"archive-${DATE}.tar.gz\"" >> ${TMPFILE_MAIL}
echo "Content-Disposition: attachment; filename=\"archive-${DATE}.tar.gz\"" >> ${TMPFILE_MAIL}
echo '' >> ${TMPFILE_MAIL}
cat archive-${DATE}.tar.gz | base64 >> ${TMPFILE_MAIL}
# mail end part.
echo '--SECTION--' >> ${TMPFILE_MAIL}
#### Sendmail Process.
cat ${TMPFILE_MAIL} | /usr/sbin/sendmail -i -t
#### Cleanup Process.
rm -rf ${TMPDIR_ATTACHMENTS}
rm archive-${DATE}.tar.gz
rm ${TMPFILE_TEXT}
rm ${TMPFILE_MAIL}
実行
標準出力にはとくに何も出力しないよう実装しましたので、成功すれば何も表示されないはずです。メールログ、受信先メールトレイなどを確認して配送状況を確認します。