カテゴリー
プログラミング

mailコマンドやPerl、Pythonに頼らずにBashだけで添付ファイル付きメールを送信する

はじめに

AmazonLinuxで新しいホストを構築していると、メール送信テストなどでメールを送信しようとしたときにmailコマンドがデフォルトで使えませんでした。この際依存をsendmailコマンドだけにしてみましたので紹介します。

 メールは添付ファイルの有無に関わらず、単なるテキストデータとしてやり取りされます。細かい取り決めはたくさんありますが、大まかな構造はさほど複雑ではありません。まずは構造を確認します。次に、具体的なBashプログラムを紹介します。

メールの構造

メールをテキストデータとしてみたとき、大まかには下記の3つのパートに区切る事ができます。

  1. 送り主、宛先、件名などが載ったヘッダーパート
  2. メール本文をBase64エンコードしたボディーパート
  3. 添付ファイルを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}

実行

標準出力にはとくに何も出力しないよう実装しましたので、成功すれば何も表示されないはずです。メールログ、受信先メールトレイなどを確認して配送状況を確認します。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください