プログラマ 福重 伸太朗 〜基本へ帰ろう〜 このページをアンテナに追加 RSSフィード

2007-12-17

Railsでドットが連続3つ(トリプルドット)以上あるメールアドレスでもActionMailer::Base.deliverを利用してメールを送信する

●何がやりたいのか

RailsActionMailer::Base.deliverを利用してメールを送信する場合、以下のようなアドレスは通常送信できないが、送信したい。

TMail 携帯メールアドレス問題 - プログラマ 福重 伸太朗 〜基本へ帰ろう〜←の対応策の一つ。

●実験

・ドットが連続3つ

C:\rails_app>ruby script/console
Loading development environment.
>> mail = TMail::Mail.new
=> #<TMail::Mail port=#<TMail::StringPort:id=0x246883e> bodyport=nil>
>> mail.to = "hoge...hoge@docomo.ne.jp"
=> "hoge...hoge@docomo.ne.jp"
>> ActionMailer::Base.deliver(mail)
=> #<TMail::Mail port=#<TMail::StringPort:id=0x246883e> bodyport=#<TMail::StringPort:id=0x246501c>>

Railsのログには以下のように残される。

Sent mail:
 To: <>

・ドットが連続2つ

C:\rails_app>ruby script/console
Loading development environment.
>> mail = TMail::Mail.new
=> #<TMail::Mail port=#<TMail::StringPort:id=0x246883e> bodyport=nil>
>> mail.to = "hoge...hoge@docomo.ne.jp"
=> "hoge...hoge@docomo.ne.jp"
>> ActionMailer::Base.deliver(mail)
=> #<TMail::Mail port=#<TMail::StringPort:id=0x246883e> bodyport=#<TMail::StringPort:id=0x246501c>>

Railsのログには以下のように残される。

Sent mail:
 To: hoge..hoge@docomo.ne.jp

上記の結果から分かるように、ドットが3つ以上のメールアドレスはToが消えてしまう。


●ドットが連続3つでもActionMailer::Base.deliverを使ってメールを送信する

結論から言うとこうやりました。

・tmail_triple_dot_measures.rb

module ActionMailer
  class Base
    def deliver!(mail = @mail)
      if "#{mail.to}" =~ /\.\.\./
        sendmail_lr = SendmailWithoutUsingActionmailer::Send.new(@from,@subject,@body)
        sendmail_lr.sendto(@recipients)
        return mail
      end
      
      raise "no mail object available for delivery!" unless mail
      logger.info "Sent mail:\n #{mail.encoded}" unless logger.nil?

      begin
        send("perform_delivery_#{delivery_method}", mail) if perform_deliveries
      rescue Exception => e  # Net::SMTP errors or sendmail pipe errors
        raise e if raise_delivery_errors
      end

      return mail
    end
  end
end

・sendmail_without_using_actionmailer.rb

module SendmailWithoutUsingActionmailer

=begin
   Example:
     class Mobile::Users::AccountController < ApplicationController
       require 'sendmail_without_using_actionmailer'
       
       def sendmail_for_triple_dot
         subject  = "テストタイトル"
         body     = "テスト本文"
         from     = "customer@#{SEND_DOMAIN}"
         to       = "hoge@docomo.ne.jp"
         sendmail = SendmailWithoutUsingActionmailer::Send.new(from,subject,body)
         sendmail.sendto( to )
       end
     end
=end

  class Send
    require "nkf"

    SENDMAIL = "/usr/sbin/sendmail"

    def initialize( from, subject, body )
      @from = from
      @subject = subject
      @body = body
    end

    def encode( str )
      require "base64"
      "=?iso-2022-jp?B?" + Base64.encode64( NKF.nkf( "-j", str ) ).chomp + "?="
    end

    def sendto( to, cc = nil, bcc = nil )
      text = "From: #{@from}\n"
      text += "To: #{to}\n"
      text += "Cc: #{cc}\n" if cc
      text += "Bcc: #{bcc}\n" if bcc
      text += "Subject: #{encode( @subject ).gsub(/\n/,'\\n') if @subject}\n"
      text += "MIME-Version: 1.0\n"
      text += "Content-Type: text/plain; charset=\"ISO-2022-JP\"\n"
      text += "Content-Transfer-Encoding: 7bit\n"
      text += "\n"
      text += NKF.nkf( "-j", @body ) + "\n"
       
      to = to.split( /,\s*/ )
      to += cc.split( /,\s*/ ) if cc
      to += bcc.split( /,\s*/ ) if bcc

      [@from,*to].each do |t|
      raise "Mail address error -> #{t}" if t !~ /^[0-9A-Za-z_\-\._]+@[0-9A-Za-z_\-\._]+$/
      end
       
      require "net/smtp"
      logger = Logger.new("#{RAILS_LOG_FILE}")

      begin
        Net::SMTP.start( 'localhost' ) do |smtp|
          smtp.send_mail text, @from, to
        end
      rescue
        #送信失敗ログを出す
        #logger.info "SENDMAIL_WITHOUT_USING_ACTIONMAILER SEND FALSE:To:\n #{to}\n" unless logger.nil?
        #logger.info "SENDMAIL_WITHOUT_USING_ACTIONMAILER SEND FALSE:Subject:\n #{@subject}\n" unless logger.nil?
        #logger.info "SENDMAIL_WITHOUT_USING_ACTIONMAILER SEND FALSE:Body:\n #{@body}\n" unless logger.nil?
        return false
      else
        #送信成功ログを出す
        #logger.info "SENDMAIL_WITHOUT_USING_ACTIONMAILER SEND TRUE:To:\n #{to}\n" unless logger.nil?
        #logger.info "SENDMAIL_WITHOUT_USING_ACTIONMAILER SEND TRUE:Subject:\n #{@subject}\n" unless logger.nil?
        #logger.info "SENDMAIL_WITHOUT_USING_ACTIONMAILER SEND TRUE:Body:\n #{@body}\n" unless logger.nil?
        return true
      end
    end
  end
end

ActionMailer::Base.deliverは使いますが、ドットを連続3つ以上含んでいたら、SendmailWithoutUsingActionmailerモジュールを使って送信すると言うやり方をやってみました。Viewのメールテンプレートもそのまま使えますので良いです。


Railsへの設置の仕方は、上記2つのファイルをRailsアプリのlibフォルダ内に入れます。


●環境

Ruby 1.8.6

Rails 1.2.3

文字コードUTF-8