diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 07e610406f2006ad1eb4e98cc4eaf6a096e73725..e00cd1060e95d0ff55b13f44b8e4b41ff96cb3d2 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -842,6 +842,7 @@ def mail(headers = {}, &block) @_mail_was_called = true create_parts_from_responses(message, responses) + wrap_inline_attachments(message) # Set up content type, reapply charset and handle parts order message.content_type = set_content_type(message, content_type, headers[:content_type]) @@ -871,7 +872,7 @@ def set_content_type(m, user_content_type, class_default) # :doc: when user_content_type.present? user_content_type when m.has_attachments? - if m.attachments.detect(&:inline?) + if m.attachments.all?(&:inline?) ["multipart", "related", params] else ["multipart", "mixed", params] @@ -969,6 +970,27 @@ def each_template(paths, name, &block) end end + def wrap_inline_attachments(message) + # If we have both types of attachment, wrap all the inline attachments + # in multipart/related, but not the actual attachments + if message.attachments.detect(&:inline?) && message.attachments.detect { |a| !a.inline? } + related = Mail::Part.new + related.content_type = "multipart/related" + mixed = [ related ] + + message.parts.each do |p| + if p.attachment? && !p.inline? + mixed << p + else + related.add_part(p) + end + end + + message.parts.clear + mixed.each { |c| message.add_part(c) } + end + end + def create_parts_from_responses(m, responses) if responses.size == 1 && !m.has_attachments? responses[0].each { |k, v| m[k] = v } diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb index c980c2d9f661135af7ec7abbb03948c7451450b9..45846481fe75f47a1f4e4ca878df305b14bd85cb 100644 --- a/actionmailer/test/base_test.rb +++ b/actionmailer/test/base_test.rb @@ -186,6 +186,20 @@ class BaseTest < ActiveSupport::TestCase assert_equal("logo.png", email.parts[1].filename) end + test "can embed an inline attachment and other attachments" do + email = BaseMailer.inline_and_other_attachments + # Need to call #encoded to force the JIT sort on parts + email.encoded + assert_equal(2, email.parts.length) + assert_equal("multipart/mixed", email.mime_type) + assert_equal("multipart/related", email.parts[0].mime_type) + assert_equal("multipart/alternative", email.parts[0].parts[0].mime_type) + assert_equal("text/plain", email.parts[0].parts[0].parts[0].mime_type) + assert_equal("text/html", email.parts[0].parts[0].parts[1].mime_type) + assert_equal("logo.png", email.parts[0].parts[1].filename) + assert_equal("certificate.pdf", email.parts[1].filename) + end + # Defaults values test "uses default charset from class" do with_default BaseMailer, charset: "US-ASCII" do diff --git a/actionmailer/test/fixtures/base_mailer/inline_and_other_attachments.html.erb b/actionmailer/test/fixtures/base_mailer/inline_and_other_attachments.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..e20087812748fbd2e6b647f2c4b9efce3334c458 --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/inline_and_other_attachments.html.erb @@ -0,0 +1,5 @@ +

Inline Image

+ +<%= image_tag attachments['logo.png'].url %> + +

This is an image that is inline

\ No newline at end of file diff --git a/actionmailer/test/fixtures/base_mailer/inline_and_other_attachments.text.erb b/actionmailer/test/fixtures/base_mailer/inline_and_other_attachments.text.erb new file mode 100644 index 0000000000000000000000000000000000000000..e161d244d27ebcaec36fe614a866aba6212ac5d1 --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/inline_and_other_attachments.text.erb @@ -0,0 +1,4 @@ +Inline Image + +No image for you + diff --git a/actionmailer/test/mailers/base_mailer.rb b/actionmailer/test/mailers/base_mailer.rb index 9f3fef23832f49c80e8dd83f8b183ee34bc915f1..4536db5e5e15c17077d70982411920bdaaef1832 100644 --- a/actionmailer/test/mailers/base_mailer.rb +++ b/actionmailer/test/mailers/base_mailer.rb @@ -44,6 +44,12 @@ def inline_attachment mail end + def inline_and_other_attachments + attachments.inline["logo.png"] = "\312\213\254\232" + attachments["certificate.pdf"] = "This is test File content" + mail + end + def attachment_with_content(hash = {}) attachments["invoice.pdf"] = "This is test File content" mail(hash)