Saving attachments with Ruby 1.9.2, Rails 3 and the Mail gem

Using the TMail gem in Rails 2 / Ruby 1.8.7, this was probably how you saved an attachment:

# tmail is a TMail object
tmail.attachments.each do |tattch|
  fn = tattch.original_filename
  File.open(fn, File::CREAT|File::TRUNC|File::WRONLY,0644) { |f| f.write( tattch.string ) }
end

…or perhaps something like this if you’re cautious:

# tmail is a TMail object
tmail.attachments.each do |tattch|
  fn = tattch.original_filename
  begin
    File.open(fn, File::CREAT|File::TRUNC|File::WRONLY,0644) { |f| f.write( tattch.string ) }
  rescue Exception => e
    logger.error "Unable to save data for #{fn} because #{e.message}"
  end
end

But if you try that in Rails 3 / Ruby 1.9.2 — which uses the new Mail gem — you’ll get a curious little error like this one (where x80 could be many different hex codes, such as xC5 or xC3):

Encoding::UndefinedConversionError Exception: "\x80" from ASCII-8BIT to UTF-8

Your first instinct might be to suspect the Mail gem itself. The problem is, in fact, not Mail’s fault; it is rooted in Ruby 1.9.2’s new string encoding mechanism. Fortunately the fix is dead simple: open the output file in binary mode.

Here is the above code snippet corrected for Rails 3 / Ruby 1.9.2 with the new Mail gem:

# tmail is now a Mail object
tmail.attachments.each do |tattch|
  fn = tattch.filename
  begin
    File.open( fn, "w+b", 0644 ) { |f| f.write tattch.body.decoded }
  rescue Exception => e
    logger.error "Unable to save data for #{fn} because #{e.message}"
  end
end

For more information about how things changed in Ruby 1.9, consider reading James Gray’s article on Ruby 1.9 string encodings.

2 thoughts on “Saving attachments with Ruby 1.9.2, Rails 3 and the Mail gem

  1. Pingback: ruby gmail undefined method `save_attachments_to’ « Lost Ferry

Leave a comment