サイズの大きなzipファイルをメールで送付するサンプル
昨日のサンプルでzipファイルの送付はできたわけですが、これだとzipの内容を一気に読んで送っているので、転送されるファイルサイズが大きくなったとき、メモリが足りなくなる問題があります。本文をStreamで指定できればいいのだけど、TMailでのやり方がよくわからなかったので、以下の戦略で何とかしてみました。
- Net::SMTP#send_mailのmailsrc引数はeachを実装した任意のオブジェクトを指定できるので、データを少しずつ返すクラスを独自に作成して指定する。
- データを少しずつ返すクラスでは、以下の処理を行う。
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位のファイルは無事送付できました。