Сохранить Mail :: Part как вложение в качестве носителя - PullRequest
0 голосов
/ 27 марта 2019

Я пытаюсь реализовать функцию, в которой мне нужно проанализировать электронную почту из s3 и извлечь ее вложения в загрузчик несущей: мне нужно сохранить Mail::Part как вложение несущей.

Я читаюэлектронное письмо, хранящееся в s3, и его разбор с использованием гема почтовой программы, поэтому я в основном получаю многочастное электронное письмо.Пока что я уже закончил разбор тела, но теперь мне нужно обработать вложения электронной почты.

Я здесь:

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">>]

И мне нужно сохранить его какcarrierwave uploader

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, но этот драгоценный камень, кажется, не содержит код, который яищу (или, может быть, я пропустил)

РЕДАКТИРОВАТЬ

Я пытаюсь следовать инструкциям отсюда 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 ]

1 голос
/ 27 марта 2019

Я не думал, что получу это, но вот оно ...

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 может что-то изменить.

0 голосов
/ 27 марта 2019

Так что на самом деле было два трюка

  • Использование флага 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, не прибегая к этому (так как файл все еще должен быть очищен / удален после)

...