紅孔雀 このページをアンテナに追加 RSSフィード

2011-10-02 Rails3 でのメール送信

Rails3 でのメール送信処理について調べました。

[] 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 の派生クラスごとに対応することにしました。