文系プログラマによるTIPSブログ

文系プログラマ脳の私が開発現場で学んだ事やプログラミングのTIPSをまとめています。

シェルスクリプトのmailコマンドでメール送信

bashでちょっとメール送信したい時ってありますよね〜


f:id:treeapps:20180424102046p:plain

CentOS・bashの環境でシェルスクリプトからメール送信する際、件名や本文が文字化けしまくり、発狂した挙句に結局rubyやpythonでメール送信処理を書いた経験があります。

やっぱりシェルスクリプトだけでメール送信したいので、ちゃんと調べて実装してみました。

#!/bin/sh

send_mail() {
    from=$1
    to=$2
    inputEncoding="utf-8"
    outputEncoding="iso-2022-jp"
    subjectHead="=?${outputEncoding}?B?"
    subjectBody="`echo "$3" | iconv -f ${inputEncoding} -t ${outputEncoding} | base64 | tr -d '\n'`"
    subjectTail="?="
    subject=${subjectHead}${subjectBody}${subjectTail}
    contents="`echo -e $4 | iconv -f ${inputEncoding} -t ${outputEncoding}`"
    echo "$contents" | mail -s "$subject" "$to" -- -f "$from"
    return $?
}

from="from@from.com"
to="to@to.com"
subject="件名です"
contents="あああ\n
いいい\n
ううう"
send_mail "$from" "$to" "$subject" "$contents"
if [ $? -eq 1 ]; then
    echo "send mail failure"
    exit 1
fi
echo "send mail success"

subjectが化ける事が多いのですが、理由はメーラーがヘッダのエンコーディングを正しく解析できていないからです。

メールのヘッダはRFCによると、=?「文字コード」?「B」?「BASE64エンコード文字列」?= となっています。

はてな区切りでイコールで先頭と末尾を囲み、B、Base64でエンコーディングしたsubjectを設定する事で、メーラーは正しくsubjectを認識できます。

本文の改行については、echoの-eオプションでエスケープの解釈を有効にすると改行されます。

1箇所ハマったところがあります。それは、CentOSのbase64コマンドは文字数が多いと勝手に改行が入る点です。手元のmacでは改行が入りませんでした。

改行のせいでヘッダが壊れ、subjectが文字化けしました。subjectBodyで tr しているのは、その改行を除去するためです。

なお、iconvはそんな優秀じゃないので、半角カタカナ等を入れると正常に処理できないかもしれません。