将Mail :: Part保存为载波附件

时间:2019-03-27 16:59:36

标签: ruby-on-rails email ruby-on-rails-5 carrierwave email-attachments

我正在尝试实现一项功能,该功能需要解析s3中的电子邮件并将其附件提取到载波上传器中:我需要将Mail::Part保存为载波附件。

我正在阅读存储在s3中的电子邮件,并使用mailer gem对其进行解析,因此我基本上得到了一个多部分的电子邮件。到目前为止,我已经完成了对正文的解析,但是现在我需要处理电子邮件附件。

我在这里:

s3 = ::Aws::S3::Encryption::Client.new(
  region: 'eu-west-1',
  kms_key_id: 'my-key',
)
object = s3.get_object(
  bucket: bucket,
  key: key,
)
s3_email = object.body.read
mail = ::Mail.new(s3_email) # Mail::Message
mail.attachments
# => [#<Mail::Part:70154514749400, Multipart: true, Headers: <Content-Type: multipart/alternative; boundary="------------0739BEA5795DFFE28DCBAECD">>, #<Mail::Part:70154514744360, Multipart: false, Headers: <Content-Type: application/pdf; x-mac-type="0"; x-mac-creator="0"; name="my_attachment.pdf">, <Content-Transfer-Encoding: base64>, <Content-Disposition: attachment; filename="my_attachment.pdf">>]

我需要将其存储为载波上传器

class Message
  include Mongoid::Document
  mount_uploader :attachment, ::AttachmentUploader
end

# Message.new(attachment: mail.attachments.first) ==> I want to do something like this

我不确定如何将其作为载波附件进行传输。

我也了解Griddler,但是这个gem似乎不包含我要寻找的代码(或者我错过了)

编辑

我正在尝试使用临时文件遵循此处https://github.com/mikel/mail#testing-and-extracting-attachments的说明,但是事情并没有按计划进行

tempfile = Tempfile.new(filename)
tempfile.write(attachment.decoded)
# => *** Encoding::UndefinedConversionError Exception: "\xFF" from ASCII-8BIT to UTF-8

2 个答案:

答案 0 :(得分:1)

我没想到我会得到,但是在这里...

attachment = mail.attachments.first
File.open('/Users/me/temp.jpg', 'w', encoding: 'ascii-8bit') do |f|
   f.write attachment.body.decoded
end

因此,这就是编写新文件的方式。但是您可以通过类似的方式使用Tempfile

f = Tempfile.new(['temp', '.jpg'], encoding: 'ascii-8bit')
f.write attachment.body.decoded
message = Message.new(attachment: File.open(f))

请告诉我这是否适合您。我通过手动将图像附加到电子邮件,然后从已发送的邮件中撤消该过程来对其进行了测试。我不确定您的AWS S3存储桶会如何改变。

答案 1 :(得分:0)

所以实际上有两个窍门

  • 使用b标志直接写入字节,从而避免了编码问题
  • 确保文件的扩展名与原始文件相同。默认情况下,使用临时文件会弄乱扩展名,并且知道carrierwave有一个扩展名白名单,这会弄乱附件的验证

以下内容对我有用

# Map attachments to files that can be added via carrierwave
email.attachments.map do |attachment|
  filename = attachment.filename
  extension = File.extname(filename)
  # Produce a nice tmpfile with human readable display name and preserve the extension 
  tempfile = Tempfile.new([File.basename(filename, extension) + '-', extension])
  # The `b` flag is important
  File.open(tempfile, 'wb') { |f| f.write(attachment.decoded) }
  tempfile
end

这样做的缺点是必须将文件写入磁盘(该文件已经在内存中解析了)。我仍然想知道是否有一种方法可以在不使用载波的情况下将文件存储在载波中(因为此后仍需要清理/删除文件)