読者です 読者をやめる 読者になる 読者になる

Mail gemでメールを転送する

ActionMailer

お客さんとメールしているうちに、なんかわけわかんなくなっちゃうことが頻発したので、なんとかしたいと思ったというのが最初。普通に関係者全員CC付けておけば、とりあえずは見える状況になるはずなんだけど、わざわざCCを抜いて返信してくるお客さんとかいるので、困る。

しょうがないので、簡単に言うと、ML的なものが欲しくなりました。

  1. メールを特別なアドレス(お客さん毎、弊社宛て)に送ると、DBに保存して、弊社の関係者に転送
  2. メールを特別なアドレス(お客さん毎、お客さん宛て)に送ると、DBに保存して、お客さんの関係者に転送。Reply-toとFromを、1のアドレスに変更して転送すれば、ちょっとやそっとじゃ関係者が取り残されるような事態にはならないはず。

今日のお話は二点です。

  1. 「メールの転送」という機能がない
  2. ヘッダが化ける件へのワークアラウンド

メールを転送できるようにする

まず、メールを転送する必要がある。メールの本文を書き換えずに、宛先だけ変更したいんだけど、その機能はMailには無さげなので、なんとかしなくちゃいけない。こんなのを書く。

require "mail"

class ::Mail::Message
  def rcpt_to(rcpt = nil)
    @rcpt_to = [] unless @rcpt_to
    
    if rcpt
      @rcpt_to << rcpt
    end

    @rcpt_to
  end
  
  def destinations
    if self.rcpt_to.empty?
      [to_addrs, cc_addrs, bcc_addrs].compact.flatten
    else
      self.rcpt_to
    end
  end
end

これを、config/initializersに置いておくと、Mail::Messageにrcpt_toというメソッドを追加します。ソースを読むと、destinationsに対してメールを送っているようなので(SMTPしか見てないけど→sendmailとかどうなるか知らん)、ここを書き換えてあげれば良いはず。

メールを転送するときは、

# email = Mail.read("message.eml")
email.rcpt_to "soutaro@example.com"
email.deliver

でOK。rcpt_toに指定したアドレスに転送されます。

ヘッダが化ける件に対するワークアラウンド

これでOKかと思いきや、そんなことはなくて、ヘッダが化ける。

化けたメッセージを見ると、こんな感じ。

Subject: =?ISO-2022-JP?Q?Re:_=E3=81=9F=E3=81=B6=E3=82=93?=

これ、日本語はUTF-8なのに、エンコード(?)するときにISO-2022-JPだって自称してるので化ける。

エンコードするのを、UTF-8じゃなくて、ISO-2022-JPに変更する方法を探したんだけど、ちょっとよくわからないので、そもそも俺がやりたいのはそういうことじゃないので、逆を考えることにした。つまり、

Subject: =?UTF-8?Q?=E6=97=A5=E6=9C=AC=E8=AA=9E=E3=81=8C=E3=81=B0=E3=81=91=E3=82=8B=E3=81=8B=3F?=

になってれば良い。

これなら簡単。

mail.header[:subject].charset = "utf-8"
mail.header[:subject].field.charset = "utf-8"

これだけで良い。headerの:subjectと:fromと:ccと:toくらいを直してあげれば、他のところはあんま日本語使いたい人いないでしょう。

感想

ヘッダのフィールドに文字セットがあるのとか、多分おかしくて、そんなの1.9なら文字列に書いてあるんだから、それを使ってしれっとエンコードすれば良いだけだと思うんだけど。さりげなくheader.charsetというのもあるんだけど、これも変じゃないのかな。ヘッダって、ASCIIの7bitしか使っちゃだめなんじゃなかったっけ。