半月ほど前の話です.毎週木曜日の演習科目で,1回だけ,それまでの課題の解答をTAと私とでレビューして,学生ごとにメールを送りました.
2年前にも実施していました*1.レビュー結果のExcelファイルをCSV形式で保存して,集計用のRubyスクリプトと,メール送信用のRubyスクリプトを,順に実行すればいいのです.
去年は,ファイルがないなあ,せんかったんかなあ….
ともあれ,2年前のプログラムを見直し,Ruby 1.9対応にしとこかと手を加えました.dry run*2はOK.そして実行とすると,さっそくエラーが出ました.
Rubyのバージョンは以下のとおり.
$ ruby -v ruby 1.9.2dev (2009-11-04 trunk 25650) [i686-linux]
スクリプトの概要はこうなっていて…
# server, header, body, from, to, ccに適切な値(文字列)を代入 # bodyの文字コードは,初めはUTF-8で,すべて格納したらbody=body.tojis Net::SMTP.start(server, 25) {|smtp| smtp.ready(from, to, cc) {|s| s.puts header s.puts s.puts body } }
エラーメッセージは
(略)/lib/ruby/1.9.1/net/protocol.rb:359:in `puts': incompatible character encodings: ISO-2022-JP and US-ASCII (Encoding::CompatibilityError)
とか,少しコードを変えても
(略)/lib/ruby/1.9.1/net/protocol.rb:305:in `slice!': incompatible encoding regexp match (US-ASCII regexp with ISO-2022-JP string) (Encoding::CompatibilityError)
とか.
protocol.rbを開いてみたものの,どうにも対策できません.
呼び出し方としてはputsメソッドですが,内部では文字列処理をしていて,そのあたりに起因するエラーなのはわかるのですが.
さてあまり時間がありません.午後の授業開始までに,メールを送り終えたいのです.授業の初めに解説をしたいし,そもそも授業中にスクリプトいじりをする時間的・精神的余裕はないでしょう….
といったところで,悪魔がささやきました.tojisしたあとのbodyを,中身(バイト列)はそのままで,エンコーディングを「US-ASCII」にすればいいじゃないかと.
やってみました:
# server, header, body, from, to, ccに適切な値を入れておく # bodyの文字コードはUTF-8 Net::SMTP.start(server, 25) {|smtp| if RUBY_VERSION >= "1.9" smtp.send_message (header + "\n" + body).tojis.force_encoding("US-ASCII"), from, to, cc else smtp.ready(from, to, cc) {|s| s.puts header s.puts s.puts body.tojis } end }
いきなり実行というのは,危険があぶないので,header生成時に「toを自分」「1通送ったら終了」とする処理を暫定的に入れて,実行すると,問題なかったようなので,暫定コードを外して実行しました.うまくいったっぽいです.「いったっぽい」というのは,実はsmtp.send_messageの呼び出しのところを
smtp.send_message (header + "\n" + body).tojis.force_encoding("US-ASCII"), from, to
と書いていて,学生に届くメールには,「Cc: 俺のアドレス」が書かれているのに,俺んとこには送っていないからでした!
インスタンスメソッドNet::SMTP#send_message*3の引数は,最初は本文,次は送信元のメールアドレス,残りは送り先のメールアドレスです.ヘッダにToとかCcとかBccとか書いていても,それは文字列と見なされるわけですね.逆に,ToにもCcにもないメールアドレスを,引数に追加すれば,それがBcc扱いになるということか….
年1回のスクリプト,来年に向けての課題は:
- 日本語を含むメールをRubyで送るための,より良い方法を知る.
- dry runオプションをつける.
*1:日記に書いたはず…と見直したところ,2年前ではなく3年前に書いていたのでした! 演習のレビュー結果を一斉送信, 一斉送信への対応 - わさっき
*2:dry runの意味・使い方・読み方 | Weblio英和辞書, http://english.kyounotubo.mond.jp/?eid=581902, http://kawama.jp/archives/2007/10/rsyncdryrun.html