【0】やりたい事
会員番号、性別、生年、姓、名、メアドの記されたテキスト会員名簿がある。
0001 f 1922 フグ田 サザエ sazae@fuguta.sazae3
0002 m 1895 磯野 波平 namihei@isono.sazae3
0003 f 1901 磯野 舟 fune@isono.sazae3
0004 m 1917 フグ田 マスオ masuo@fuguta.sazae3
0005 m 1938 磯野 カツオ bonito@isono.sazae3
0006 f 1942 磯野 ワカメ wakame@isono.sazae3
0007 m 1947 フグ田 タラオ tarao@fuguta.sazae3
0008 ? ? 磯野 タマ tama@isono.sazae3
この人々にメールマガジンを送る。ただし宛先にはBcc:フィールドを用いて、会員同士にはアドレスが知られないようにすること。
……という作業を、シェルスクリプトを使って、しかもスマートに行う、というのがお題である。
0.1. そもそもシェルスクリプトでメール送れる?
送れる。sendmailコマンドさえあれば。あとはsedやAWKなど、POSIXの範囲のコマンドをシェルスクリプトから呼ぶだけで済むので他に何も要らない。
メール中に、UTF-8などの8bit文字があっても大丈夫。こんなこともあろうかとsendjpmailという、自動的に7bit化して送るラッパーコマンドを作っておいた。→シェルスクリプトでメール送信、「さようならnkf」編
【1】 必要なもの
必要なものは次の3つ。最初のやつはメール送信に必須なのでこれが無いとお話にならない。
あとの2つは、本当は無くてもいいけどスマートなシェルスクリプトを書くために補助的に用いるものだ。中身はPOSIXの範囲で書かれたシェルスクリプトなので、ただダウンロードしておけばいいだけ。他に何も要らないし、もちろんコンパイルも不要。
- sendmailコマンドの使えるUNIXホスト(なければPostfixあたりをインストール)
- sendjpmailコマンド(拙作のsendmailコマンドラッパー)
- filehameコマンドのPOSIX準拠版(無くてもいいけどシンプルなシェルスクリプトを書くために利用)
【2】 送り方
1) メールのテンプレートを用意
メルマガの文面を作る。注意すべき点は次の3つ。
- ヘッダーセクションと本文セクションの間に必ず空行を挿むこと
- マルチバイト文字を使う場合はUTF-8で
- 実際の宛名を書き込むBCCフィードは、
###BCCFIELD###
というマクロ文字列にしておく
From: スタッフ1号 <staff1@sazae3.anime-pro>
To: スタッフ1号 <staff1@sazae3.anime-pro>
### BCCFIELD###
Subject: [磯野家メルマガ] いよいよ今日、放送日です
磯野家キャストの皆様
今晩は、スタッフ1号です。
出演者皆様のおかげによりまして、本日も放送当日を迎えることが出来ました。
ありがとうございました。
さーて、今日のサザエさんは、
-----
▽スーパーのお姉さん
▽姉さんの迷アドバイス
▽かわいい焼きもち
-----
の3本です。ご確認ください。
追伸:
次回予告のジャンケンの手は、
放送終了まで「絶対に」公言せぬようくれぐれもご注意ください。
2) シェルスクリプトを作成
次のようなシェルスクリプトを作る。
# ! /bin/sh
[ -f "${1:-}" ] || {
echo "Usage: ${0##*/} <mail_template>" 2>&1
exit 1
}
cat members.txt |
awk '{print $5}' | # メアド列だけ取り出す
sed 's/^.*$/ <&>/' | # メアド文字列をインデントしつつ"<>"で囲む
sed '1s/^/Bcc:/' | # 最初の行にだけ、行頭に"Bcc:"を付ける
sed '$!s/$/,/' | # 最後の行以外にだけ、行末にカンマを付ける
filehame -lBCCFIELD "$1" | # テンプレートにメアドをハメる
sendjpmail # UTF-8を7bit化してメールを一括送信
後ろの2つのsedコマンドはアドレス範囲指定を併用しているので若干高度な使用法かもしれない。
さて、このシェルスクリプトのスマートなところは、テンポラリーファイルもループ構文も使っていないところ(ループ処理はコマンドの中に隠蔽されている)。おかげで、このシェルスクリプトは上から下へ読むだけで済むので可読性が非常に高いし、コメントだけ残せばそれが処理の手順書になってしまう。
ループ構文を完全に無くせた理由は、sendjpmail、もといsendmailコマンドの特長にもよる。Bcc: フィールドに全員のメアドを記入したテキストを用意すれば、send(jp)mailコマンドを一回呼び出すだけで済み、while文など使って人数の分だけ呼び出す必要をなくせるからだ。
3) 送信
あとは、filemaheコマンドと、sendjpmailコマンドに実行権限とパスを通した状態で、
$ ./send_mailmag.sh mailmag20150426.txt
を実行すればおしまい。
【3】応用(性別、年代で絞り込む)
元の会員情報テキストには、性別と年代の情報もあるのでこれで絞り込み、成人男性だけに奥様にはナイショのミミヨリなメルマガを送信する、といった応用も可能だ。
先ほどのシェルスクリプトのcat行の次に、2つほどAWKコマンドを足せばよい。
# ! /bin/sh
[ -f "${1:-}" ] || {
echo "Usage: ${0##*/} <mail_template>" 2>&1
exit 1
}
cat members.txt |
awk '$3<='"$(($(date +%Y)-20))" | # オトナ(20歳以上)だけに絞り込む
awk '$2=="m"' | # オトコだけに絞り込む
awk '{print $5}' | # メアド列だけ取り出す
sed 's/^.*$/ <&>/' | # メアド文字列をインデントしつつ"<>"で囲む
sed '1s/^/Bcc:/' | # 先頭の行にだけ、行頭に"Bcc:"を付ける
sed '$!s/$/,/' | # 最後の行以外にだけ、行末にカンマを付ける
filehame -lBCCFIELD "$1" | # テンプレートにメアドをハメる
sendjpmail # UTF-8を7bit化してメールを一括送信
最初のcatとAWK3つ、それとsed3つをそれぞれ1行にまとめろという声が聞こえてきそうだが、それは敢えてしない。可読性が低下するし、最後にメール送信という桁違いにコストの高い処理が待ち構えているのにパフォーマンスに凌ぎを削る必要を感じないから。
それはそうと、これだとカツオくん(永遠の11歳)にもイケナいメールが送られてしまうぞ。イカン!!