コマンドラインからモノスペースのメールを送る

2025/02/13に公開

Linuxのshellからモノスペースのメールを送る方法を調べましたので記しておきます。

  • Debian 12

メールのContent-Typetext/htmlにし、コンテンツを<html><pre></pre></html>で囲むとモノスペースになります。

なぜモノスペースにしたいか

Linuxのmailコマンドは標準入力をメール本文として送ることができる手軽なコマンドです。例えば、以下のようにして本文Helloをrootに送ることができます。

echo Hello | mail -s 'Greeting' root

しかしながら、このメールはプレインテキストであるため、ほとんどのMUAはプロポーショナルフォントで本文を表示します。人間が書く文章ならそれでいいのですが、コマンド出力をメールで送る場合は不都合があります。例えば、dfコマンドがそれです。

df | mail -s 'Greeting' root

dfコマンドは端末がmonospaceであることを仮定してテキストにフォーマットをかけています。しかし、プレインテキストのメールとして送ると、MTAではフォーマットが崩れます。たとえば、Gmailで受信するとこのようになります。

これでは読みにくいため、モノスペースを送る側で強制したいというのが動機です。

モノスペースのメールを送る

モノスペースのメールを送るには

  • コンテンツにHTMLタグを付加して
  • メールヘッダに text/html を指定

する必要があります。

HTMLタグの付加

送りたいコンテンツの前後にHTMLタグを付加します。これはechoコマンドでできます。

 (echo '<html><pre>' ; df; echo '</pre></html>') 

()はサブシェルです。サブシェル内で実行したプログラムの標準出力はひとつにまとめられます。結果的にecho, df, echo プログラムの出力が順番にサブシェルの標準出力として出てきます。

これでコンテンツ側は終わりです。

メールヘッダの付加

メールヘッダを追加してtext/htmlを指定するには、mailコマンドの-aオプションを使います。例えば、rootに送るのであれば。

mail -s 'Subject' -a 'Content-Type: text/html' root

とします。

結果

以上を組み合わせると、コマンドは以下のようになります。

(echo '<html><pre>' ; df; echo '</pre></html>') | mail -s 'monospace mail' -a 'Content-Type: text/html' root

Gmailでこのメールを受け取ると、

となり、モノスペースで表示されているとわかります。

応用

モノスペースのメールがレポートとして読みやすいことを利用して、cronから定期的にコンピュータの情報を遅らせる使い方があります。

比較的シンプルな例

例えば、SSDの状態を週に一度レポートしたいときには、

sudo crontab -e

を実行して、エディタの中で次の一行を追加します。

0 0 * * 1 ( echo '<html><pre>' ; df; echo; free; echo;  /sbin/smartctl -A -H /dev/nvme0n1; /sbin/nvme error-log /dev/nvme0 -e 1 ; echo '</pre></html>' ) | mail -s 'Physics server health report' -a 'Content-Type: text/html' root

これで、毎週月曜日の午前0時に以下のプログラムの実行結果がモノスペースのメールで送られてきます。メール本文を組み立てる部分を行単位にばらすと以下のようになります。

echo '<html><pre>'  
df
echo
free
echo
/sbin/smartctl -A -H /dev/nvme0n1
/sbin/nvme error-log /dev/nvme0 -e 1 
echo '</pre></html>' 

もっと複雑な例

以下はかなり複雑なcrontabの例です。

0 0 * * 1 ( echo '<html><pre>' ; df; echo; free; echo;  /sbin/smartctl -A -H /dev/nvme0n1; /sbin/nvme error-log /dev/nvme0 -e 1 ;echo;  ( typefile=`mktemp`; tempfile=`mktemp`;  cat /sys/class/thermal/thermal_zone*/temp > "$tempfile" ; cat /sys/class/thermal/thermal_zone*/type > "$typefile"; paste "$typefile" "$tempfile" | column  -t | sed 's/\(.\)..$/.\1℃/'; rm "$typefile" "$tempfile" ); echo '</pre></html>' )  | mail -s 'Physics server health report' -a 'Content-Type: text/html' root;

先の例と同じように本文を組み立てる部分を行単位にばらすとこうなります。

echo '<html><pre>' ; 
df; 
echo; 
free; 
echo;  
/sbin/smartctl -A -H /dev/nvme0n1; 
/sbin/nvme error-log /dev/nvme0 -e 1 ;
echo;  
( 
    typefile=`mktemp`; 
    tempfile=`mktemp`;  
    cat /sys/class/thermal/thermal_zone*/temp > "$tempfile"; 
    cat /sys/class/thermal/thermal_zone*/type > "$typefile"; 
    paste "$typefile" "$tempfile" \
    | column  -t \
    | sed 's/\(.\)..$/.\1℃/';
    rm "$typefile" "$tempfile";
);
 echo '</pre></html>'

/sbin/nvmeコマンドまでは最初の例と同じです。

pasteコマンドはふたつのファイルを連結するコマンドです。catコマンドが列を重ねる(垂直)方向で連結するのに対して、pasteコマンドは行を重ねる(水平)方向に連結します。

pasteコマンドが連結しているのは、/sysファイルシステムにあるプロセッサの温度センサー名typeとその値tempです。この結果はcolumnコマンドに送られて人間が読みやすいように表形式に整えられます。最後に、sedコマンドで温度の値(ミリ度単位)を整形して読みやすい表示にしています。

送られてきたメールから温度の部分だけ抜粋すると以下のようになります。

acpitz          30.0℃
pch_cannonlake  30.0℃
x86_pkg_temp    36.0℃

履歴

  • 2025/Feb/24 : 応用における、crontabの設定を修正。曜日を1に変更。曜日の指定が0だったため、メールを全く送らない設定だった。
  • 2025/Mar/17 : 応用に複雑な例を追加。その後、ファイルの削除忘れを修正。

Discussion