読者です 読者をやめる 読者になる 読者になる
無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

サイズの大きなzipファイルをメールで送付するサンプル

Ruby

昨日のサンプルでzipファイルの送付はできたわけですが、これだとzipの内容を一気に読んで送っているので、転送されるファイルサイズが大きくなったとき、メモリが足りなくなる問題があります。本文をStreamで指定できればいいのだけど、TMailでのやり方がよくわからなかったので、以下の戦略で何とかしてみました。

  • Net::SMTP#send_mailのmailsrc引数はeachを実装した任意のオブジェクトを指定できるので、データを少しずつ返すクラスを独自に作成して指定する。
  • データを少しずつ返すクラスでは、以下の処理を行う。
    • 最初にヘッダを返す。ヘッダ部分はTMailを使って作成したものを使う。
    • 次に、ファイルから少しずつデータを読んで、Base64エンコードして返す。
require 'rubygems'
require 'tmail'
require "tlsmail"
require "base64"


# tmailでメールを作成/ヘッダ部分はTMailを使って作る。
mail = TMail::Mail.new
mail.to = 'foo@var.com'
mail.from = 'foo@gmail.com'
mail.subject = 'test mail4'
mail.date = Time.now
mail.mime_version = '1.0'
mail.set_content_type 'application','zip','name'=>"test.zip"
mail.set_content_disposition 'attachment','filename'=>"test.zip"
mail.transfer_encoding = 'base64'

# Net::SMTP#sendmailの引数とするクラス。
class Body
  def initialize( mail, file )
    @mail = mail # ヘッダの取得先TMail::Mail
    @file = file # 添付するファイル
  end
  def each
    # 最初にヘッダ
    yield @mail.encoded
    # 次に本文を少しづつ読んで返す。
    open( @file, "r" ) {|io|
      while( data = io.read(1024*100*3) ) # 3の倍数にすること!
        yield Base64.encode64(data)
      end
    }
  end
end

Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE)
Net::SMTP.start( "smtp.gmail.com",  587, "localhost.localdomain", "foo@gmail.com", "<パスワード>", "plain"){ |smtp| 
  smtp.sendmail( Body.new( mail, "./test.zip" ), mail.from, mail.to) 
}

10MB位のファイルは無事送付できました。