【问题标题】:Save a Mail::Part as a carrierwave attachment将 Mail::Part 保存为载波附件
【发布时间】:2019-08-18 08:19:06
【问题描述】:

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

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

我在这里:

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

我不确定如何将其作为 Carrierwave 附件传输。

另外,我知道 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

【问题讨论】:

  • 你能做到吗? mail.attachments.filename #=&gt; 'test.png' 按文件名或索引返回附件。然后您可以将该响应包装在Message.new(attachment: File.open('test.png''))?还是那行不通?
  • 我已经编辑了我的问题。我正在阅读来自 AWS S3 文件的多部分电子邮件,所以我所拥有的只是“原始”多部分文件和邮件程序 gem 中的解析版本。我不知道如何将附件多部分版本提取到文件中,这就是我想要做的 ^^ 类似email.attachments.first.to_file 的东西,除了这不起作用

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


【解决方案1】:

所以实际上有两个技巧

  • 使用b标志直接写入字节,避免了编码问题
  • 确保文件与原始文件具有相同的扩展名。默认情况下,使用 Tempfiles 会弄乱扩展,并且知道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

这样做的缺点是必须将文件写入磁盘(而该文件已在内存中解析)。我仍然想知道是否有一种方法可以将文件存储在carrierwave中而不必求助于它(因为之后仍然需要清理/删除文件)

【讨论】:

    【解决方案2】:

    我不认为我会得到它,但它在这里......

    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 存储桶会如何改变事情。

    【讨论】:

    • 谢谢,在重新阅读了邮件gem github和一些相关问题/github问题后,我发现b标志在打开文件时实际上相当重要,并且会自动避免这些问题必须编写编码。同样在没有预防措施的情况下使用临时文件会在扩展名之后添加 uid,这有点搞乱 Carrierwave 验证行为。
    • 我们的解决方案有些相似。您对扩展名是正确的,我清理了它,但是使用 b 标志本质上是您的编码 AFAIK 的别名,所以我认为这并没有好得多。 TempFile 在文件名中注入该数据非常难看,但我认为对此无能为力!
    猜你喜欢
    • 2013-06-28
    • 2020-02-22
    • 1970-01-01
    • 2012-07-29
    • 1970-01-01
    • 2016-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多