Fixes issue #2894 - Emails with binary body (attachment as body) get handled as if they were text messages which breaks the attachment.

This commit is contained in:
Mantas Masalskis 2020-01-28 10:42:40 +01:00 committed by Thorsten Eckel
parent 264853dcbe
commit 6692869dd8
3 changed files with 84 additions and 27 deletions

View file

@ -574,40 +574,50 @@ process unprocessable_mails (tmp/unprocessable_mail/*.eml) again
def collect_attachments(mail) def collect_attachments(mail)
attachments = [] attachments = []
# Add non-plaintext body as an attachment attachments.push(*get_nonplaintext_body_as_attachment(mail))
if mail.html_part&.body.present? ||
(!mail.multipart? && mail.mime_type.present? && mail.mime_type != 'text/plain')
message = mail.html_part || mail
filename = message.filename.presence ||
(message.mime_type.eql?('text/html') ? 'message.html' : '-no name-')
headers_store = {
'content-alternative' => true,
'original-format' => message.mime_type.eql?('text/html'),
'Mime-Type' => message.mime_type,
'Charset' => message.charset,
}.reject { |_, v| v.blank? }
attachments.push({ data: body_text(message),
filename: filename,
preferences: headers_store })
end
mail.parts.each do |part| mail.parts.each do |part|
attachments.push(*gracefully_get_attachments(part, attachments, mail))
new_attachments = get_attachments(part, attachments, mail).flatten.compact
attachments.push(*new_attachments)
rescue => e # Protect process to work with spam emails (see test/fixtures/mail15.box)
raise e if (fail_count ||= 0).positive?
(fail_count += 1) && retry
end end
attachments attachments
end end
def get_nonplaintext_body_as_attachment(mail)
if !(mail.html_part&.body.present? || (!mail.multipart? && mail.mime_type.present? && mail.mime_type != 'text/plain'))
return
end
message = mail.html_part || mail
if !mail.mime_type.starts_with?('text/') && mail.html_part.blank?
return gracefully_get_attachments(message, [], mail)
end
filename = message.filename.presence || (message.mime_type.eql?('text/html') ? 'message.html' : '-no name-')
headers_store = {
'content-alternative' => true,
'original-format' => message.mime_type.eql?('text/html'),
'Mime-Type' => message.mime_type,
'Charset' => message.charset,
}.reject { |_, v| v.blank? }
[{
data: body_text(message),
filename: filename,
preferences: headers_store
}]
end
def gracefully_get_attachments(part, attachments, mail)
get_attachments(part, attachments, mail).flatten.compact
rescue => e # Protect process to work with spam emails (see test/fixtures/mail15.box)
raise e if (fail_count ||= 0).positive?
(fail_count += 1) && retry
end
def get_attachments(file, attachments, mail) def get_attachments(file, attachments, mail)
return file.parts.map { |p| get_attachments(p, attachments, mail) } if file.parts.any? return file.parts.map { |p| get_attachments(p, attachments, mail) } if file.parts.any?
return [] if [mail.text_part&.body&.encoded, mail.html_part&.body&.encoded].include?(file.body.encoded) return [] if [mail.text_part&.body&.encoded, mail.html_part&.body&.encoded].include?(file.body.encoded)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long