2011-10-02 Rails3 でのメール送信
Rails3 でのメール送信処理について調べました。
■[Ruby on Rails] Rails3 のメール送信で本文を 8bit で送信する
というわけで困ってたんですが、さっきspecを見たりしながら調べたら、どうもMail::Message#transport_encodingを8bitに設定すればよいようです。
Rails3で送信するメールの本文をbase64ではなく8bitにする方法 - 思っているよりもずっとずっと人生は短い。
Rails3 で何も設定を行わずにメール送信を行うと、本文が base64 エンコーディングされたのですが、以下のように transport_encoding = '8bit' を指定すれば UTF-8 のまま送信されるようです。
mail = Mailer.notice('お知らせです') mail.transport_encoding = '8bit' mail.deliver
メールを送信する全ての箇所を上記のように書き換えるのは手間なので、次のように mail メソッドを置き換えて、デフォルトで transport_encoding = '8bit' を設定するようにしました。*1
# app/mailers/mailer.rb class Mailer < ActionMailer::Base def notice(body) @body = body mail(:to => 'xxx@example.com') end protected def mail_with_default_settings(headers={}, &block) mail_without_default_settings(headers, &block).tap do |mail| mail.transport_encoding = '8bit' end end alias_method_chain :mail, :default_settings end
■ [Ruby on Rails] Ruby1.9 + Rails3 でメール送信時に出力される警告の対応
Ruby1.9 + Rails3 でメール送信を行ったときに、以下のような警告が出力されました。
(省略)/ruby-1.9.2-p136/lib/ruby/1.9.1/net/protocol.rb:305: warning: regexp match /.../n against to UTF-8 string
原因は net/protocol.rb の 305 行目において、エンコーディングが UTF-8 である(ASCII-8BIT ではない)文字列に対して n オプションを指定した正規表現でマッチさせているため。正規表現の n オプションを指定するとバイト列として扱われますが、マルチバイト文字に対して n オプションを指定した正規表現を使用しているため、上記警告が出力されます。
対処法としては次のアプローチが考えられますが、n オプションを指定した正規表現でマッチさせる側で対象の文字列のエンコーディングを ASCII-8BIT にするべきだと考えたので、(A) の対応を行いました。
- (A) 警告が出ている箇所の直前で文字列を ASCII-8BIT に変更するように net/protocol.rb を修正するパッチを作成する。
- (B) ASCII-8BIT にエンコーディングを設定した文字列を渡すように ActionMailer を修正するパッチを作成する。
作成したパッチ:
# config/initializers/net_protocol_patch.rb require 'net/protocol' class Net::InternetMessageIO private def each_crlf_line_with_force_encoding(src) buffer_filling(@wbuf, src) do @wbuf.force_encoding('ASCII-8BIT') while line = @wbuf.slice!(/\A.*(?:\n|\r\n|\r(?!\z))/n) yield line.chomp("\n") + "\r\n" end end end alias_method_chain :each_crlf_line, :force_encoding end
*1:PC 向けのメール送信と携帯向けのメール送信で設定を変えたい、という場合もあるはずなので、ActionMailer::Base#mail を直接変更するのではなく、ActionMailer::Base の派生クラスごとに対応することにしました。