Railsで携帯メールの添付ファイルをアップロード

今回は携帯メールに添付された画像の受信テストをRailsを行ってみます。

http://www.techscore.com/tech/OtherTech/rubyonrails/4.html
もともと、やりたいことは↑です。↑を読んでから読むとより理解しやすいと思います。
今回はテストも書いてます。

全体の流れは、
携帯のメールを .forward を使いRailsに転送し、
Action Mailerクラスのreceive() で受け取り保存するというものです。
recive()のパラメータは、受信した電子メールに対応する
TMail::Mailオブジェクトです。


1.まず、受信したメールを処理するクラスを作る

>ruby script/generate mailer MailAttachedHandler
      exists  app/models/
      create  app/views/mail_attached_handler
      exists  test/unit/
      create  test/fixtures/mail_attached_handler
      create  app/models/mail_attached_handler.rb
      create  test/unit/mail_attached_handler_test.rb

2.テスト用の添付ファイル付きメールを準備(携帯をシミュレートしています)(test\unit\mail_template\mail_attached_test.txt)(文字コードはUTF8で保存してあります・・・日本語使ってないのであまり関係ないかも・・)

From: hoge <hoge1111-test@t.vodafone.ne.jp>
Received: from mmrts035p01c.softbank.ne.jp (mmrts035p01c.softbank.ne.jp [210.228.189.207])
	2007-10-18 15:34:35.651591
		by hogehoge.com (8.13.1/8.13.1) with SMTP id l9I6YXSS018209
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="M:ZKU4eqBOmwY3WU_911T"
Date: Thu, 18 Oct 2007 15:34:33 +0900
Message-Id: <20071018153433099044.7166@0016E68C4270>
Subject: mail test
To: hoge@foo.com
Sender: hoge1111-test@t.vodafone.ne.jp
X-Priority: 3

--M:ZKU4eqBOmwY3WU_911T
Content-Type: text/plain; charset="ISO-2022-JP"
Content-Transfer-Encoding: 7bit

aaaaa
--M:ZKU4eqBOmwY3WU_911T
Content-Type: image/jpeg;name="test.JPG"
Content-Disposition: attachment;filename="test.JPG"
Content-Transfer-Encoding: base64

/9j/4QFYRXhpZgAATU0AKgAAAAgACgEOAAIAAAAJAAAAhgEPAAIAAAAIAAAAkAEQAAIAAAAFAAAA
mAESAAMAAAABAAEAAAEaAAUAAAABAAAAngEbAAUAAAABAAAApgEoAAMAAAABAAIAAAEyAAIAAAAU
AAAArgITAAMAAAABAAIAAIdpAAQAAAABAAAAwgAAAAB1bnRpdGxlZAAAVE9TSElCQQA5MTFUAAAA
AABIAAAAAQAAAEgAAAABMjAwNzoxMDoxNyAxMzo1Mjo0MAAACJAAAAcAAAAEMDIyMJADAAIAAAAU
AAABKJAEAAIAAAAUAAABPJEBAAcAAAAEAQIDAKAAAAcAAAAEMDEwMKABAAMAAAABAAEAAKACAAQA
AAABAAAA8KADAAQAAAABAAABQAAAAAAyMDA3OjEwOjE3IDEzOjUyOjQwADIwMDc6MTA6MTcgMTM6
NTI6NDAA/9sAhAADAgIDAgIDAwMDBAMDBAUIBQUEBAUKBwcGCAwKDAwLCgsLDQ4SEA0OEQ4LCxAW
EBETFBUVFQwPFxgWFBgSFBUUAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU
FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJ
CgsBAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKCxAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIh
MUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpT
VFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5
usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6EQACAQIEBAMEBwUEBAABAncA
AQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6
Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeo
qaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/wAARCAFAAPAD
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

--M:ZKU4eqBOmwY3WU_911T--

3.テストを書く(test\unit\mail_attached_handler_test.rb)

require File.dirname(__FILE__) + '/../test_helper'

class MailAttachedHandlerTest < Test::Unit::TestCase
  FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures'
  CHARSET = "iso-2022-jp"
  fixtures :users,:photos
  include ActionMailer::Quoting

  def setup
    ActionMailer::Base.delivery_method = :test
    ActionMailer::Base.perform_deliveries = true
    ActionMailer::Base.deliveries = []
  end

  def test_receive
    count = Photo.count
    MailAttachedHandler.receive(File.new(File.dirname(__FILE__) + '/../mail_template/mail_attached_test.txt',"r").read)
    assert_equal 1,Photo.find(count+1).user_id
    assert_equal "1_original.jpg",Photo.find(count+1).original
    assert_equal "1_best.jpg",Photo.find(count+1).best
    assert_equal "1_small.jpg",Photo.find(count+1).small
  end

  private
    def read_fixture(action)
      IO.readlines("#{FIXTURES_PATH}/mail_attached_handler/#{action}")
    end

    def encode(subject)
      quoted_printable(subject, CHARSET)
    end
end


4.実装する
・app\models\mail_atached_handler.rb

class MailAttachedHandler < ActionMailer::Base
  def receive(email)
    Photo.regist_profile_photo_open(email)
  end
end

・photo.rb(オリジナルファイルと、オリジナルファイルからベストサイズ、スモールサイズを作成し3種類保存する)

class Photo < ActiveRecord::Base
  belongs_to(:user)
  validates_presence_of :user_id
  validates_length_of :original, :maximum => 255
  validates_length_of :best,     :maximum => 255
  validates_length_of :small,    :maximum => 255

  def self.regist_profile_photo_open(email)
    if User.entried_address?(email.from[0])
      user = User.find_by_mailaddress(email.from[0])
      unless Photo.find_by_user_id(user.id)
        self.create_photo_table(email,user,self.create_photo_name(user))
      end
      if email.has_attachments?
        self.create_image_original(email.attachments[0],self.create_photo_name(user))
        self.create_image_best(email.attachments[0],self.create_photo_name(user))
        self.create_image_small(email.attachments[0],self.create_photo_name(user))
      end
    end
  end

  def self.create_photo_name(user)
    photo_name = {}
    original_name = "#{user.id}_original.jpg"
    best_name     = "#{user.id}_best.jpg"
    small_name    = "#{user.id}_small.jpg"
    photo_name["original"] = original_name 
    photo_name["best"]     = best_name 
    photo_name["small"]    = small_name  
    photo_name
  end

  def self.create_photo_table(email,user,photo_name)
    photo = Photo.new
    photo.user_id  = user.id
    photo.original = photo_name["original"]
    photo.best     = photo_name["best"]
    photo.small    = photo_name["small"]
    photo.save
  end

  def self.create_image_original(file,photo_name)
    File.open("#{OPEN_PROFILE_IMAGE_PATH}#{photo_name['original']}", "w+b"){ |f| f.write(file.read) }
  end

  def self.create_image_best(file,photo_name)
    ##bestサイズにする処理もする
    File.open("#{OPEN_PROFILE_IMAGE_PATH}#{photo_name['best']}", "w+b"){ |f| f.write(file.read) }
  end

  def self.create_image_small(file,photo_name)
    ##smallサイズに処理もする
    File.open("#{OPEN_PROFILE_IMAGE_PATH}#{photo_name['small']}", "w+b"){ |f| f.write(file.read) }
  end
end

これで、できるはず。

※注意
Windows環境で上記のコードを実行すると、しっかりと画像ファイルができるのですが、Linux環境で行うと、しっかりと画像ファイルが作成されない。なぜだか研究中です。


※試した環境
OS : Windows XP
Ruby : 1.8.6
Rails : 1.2.3

TMailはWindowsがRails1.2.3をインストールしたときのデフォルトで、Linuxの方は最新の0.10.8をインストールしました。これのせいかな・・・??