diff options
-rw-r--r-- | actionmailer/actionmailer.gemspec | 2 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/base.rb | 39 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/mail_helper.rb | 5 | ||||
-rw-r--r-- | actionmailer/test/base_test.rb | 17 | ||||
-rw-r--r-- | actionmailer/test/fixtures/base_mailer/inline_attachment.html.erb | 5 | ||||
-rw-r--r-- | actionmailer/test/fixtures/base_mailer/inline_attachment.text.erb | 4 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/asset_tag_helper.rb | 7 | ||||
-rw-r--r-- | actionpack/test/template/asset_tag_helper_test.rb | 9 | ||||
-rw-r--r-- | railties/guides/source/3_0_release_notes.textile | 1 | ||||
-rw-r--r-- | railties/guides/source/action_mailer_basics.textile | 31 |
10 files changed, 115 insertions, 5 deletions
diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec index 1e34352f53..2b7c21b3f2 100644 --- a/actionmailer/actionmailer.gemspec +++ b/actionmailer/actionmailer.gemspec @@ -20,5 +20,5 @@ Gem::Specification.new do |s| s.has_rdoc = true s.add_dependency('actionpack', version) - s.add_dependency('mail', '~> 2.2.2') + s.add_dependency('mail', '~> 2.2.3') end diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 3a82979d35..7da033b6af 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -36,6 +36,9 @@ module ActionMailer #:nodoc: # * <tt>attachments[]=</tt> - Allows you to add attachments to your email in an intuitive # manner; <tt>attachments['filename.png'] = File.read('path/to/filename.png')</tt> # + # * <tt>attachments.inline[]=</tt> - Allows you to add an inline attachment to your email + # in the same manner as <tt>attachments[]=</tt> + # # * <tt>headers[]=</tt> - Allows you to specify any header field in your email such # as <tt>headers['X-No-Spam'] = 'True'</tt>. Note, while most fields (like <tt>To:</tt> # <tt>From:</tt> can only appear once in an email header, other fields like <tt>X-Anything</tt> @@ -173,7 +176,7 @@ module ActionMailer #:nodoc: # # class ApplicationMailer < ActionMailer::Base # def welcome(recipient) - # attachments['free_book.pdf'] = { :data => File.read('path/to/file.pdf') } + # attachments['free_book.pdf'] = File.read('path/to/file.pdf') # mail(:to => recipient, :subject => "New account information") # end # end @@ -184,6 +187,34 @@ module ActionMailer #:nodoc: # and the second being a <tt>application/pdf</tt> with a Base64 encoded copy of the file.pdf book # with the filename +free_book.pdf+. # + # = Inline Attachments + # + # You can also specify that a file should be displayed inline with other HTML. For example a + # corporate logo or a photo or the like. + # + # To do this is simple, in the Mailer: + # + # class ApplicationMailer < ActionMailer::Base + # def welcome(recipient) + # attachments.inline['photo.png'] = File.read('path/to/photo.png') + # mail(:to => recipient, :subject => "Here is what we look like") + # end + # end + # + # And then to reference the image in the view, you create a <tt>welcome.html.erb</tt> file and + # make a call to +image_tag+ passing in the attachment you want to display and then call + # +url+ on the attachment to get the relative content id path for the image source: + # + # <h1>Please Don't Cringe</h1> + # + # <%= image_tag attachments['photo.png'].url -%> + # + # As we are using ActionView's +image_tag+ method, you can pass in any other options you want: + # + # <h1>Please Don't Cringe</h1> + # + # <%= image_tag attachments['photo.png'].url, :alt => 'Our Photo', :class => 'photo' -%> + # # = Observing and Intercepting Mails # # Action Mailer provides hooks into the Mail observer and interceptor methods. These allow you to @@ -612,7 +643,11 @@ module ActionMailer #:nodoc: when user_content_type.present? user_content_type when m.has_attachments? - ["multipart", "mixed", params] + if m.attachments.detect { |a| a.inline? } + ["multipart", "related", params] + else + ["multipart", "mixed", params] + end when m.multipart? ["multipart", "alternative", params] else diff --git a/actionmailer/lib/action_mailer/mail_helper.rb b/actionmailer/lib/action_mailer/mail_helper.rb index aab6e12387..b708881edf 100644 --- a/actionmailer/lib/action_mailer/mail_helper.rb +++ b/actionmailer/lib/action_mailer/mail_helper.rb @@ -32,5 +32,10 @@ module ActionMailer def message @_message end + + # Access the message attachments list. + def attachments + @_message.attachments + end end end diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb index 54bf3de6af..b9226196fd 100644 --- a/actionmailer/test/base_test.rb +++ b/actionmailer/test/base_test.rb @@ -33,6 +33,11 @@ class BaseTest < ActiveSupport::TestCase mail(hash) end + def inline_attachment + attachments.inline['logo.png'] = "\312\213\254\232" + mail + end + def attachment_with_content(hash = {}) attachments['invoice.pdf'] = 'This is test File content' mail(hash) @@ -264,6 +269,18 @@ class BaseTest < ActiveSupport::TestCase assert_equal("application/pdf", email.parts[1].mime_type) assert_equal("VGhpcyBpcyB0ZXN0IEZpbGUgY29udGVudA==\r\n", email.parts[1].body.encoded) end + + test "can embed an inline attachment" do + email = BaseMailer.inline_attachment + # Need to call #encoded to force the JIT sort on parts + email.encoded + assert_equal(2, email.parts.length) + assert_equal("multipart/related", email.mime_type) + assert_equal("multipart/alternative", email.parts[0].mime_type) + assert_equal("text/plain", email.parts[0].parts[0].mime_type) + assert_equal("text/html", email.parts[0].parts[1].mime_type) + assert_equal("logo.png", email.parts[1].filename) + end # Defaults values test "uses default charset from class" do diff --git a/actionmailer/test/fixtures/base_mailer/inline_attachment.html.erb b/actionmailer/test/fixtures/base_mailer/inline_attachment.html.erb new file mode 100644 index 0000000000..e200878127 --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/inline_attachment.html.erb @@ -0,0 +1,5 @@ +<h1>Inline Image</h1> + +<%= image_tag attachments['logo.png'].url %> + +<p>This is an image that is inline</p>
\ No newline at end of file diff --git a/actionmailer/test/fixtures/base_mailer/inline_attachment.text.erb b/actionmailer/test/fixtures/base_mailer/inline_attachment.text.erb new file mode 100644 index 0000000000..e161d244d2 --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/inline_attachment.text.erb @@ -0,0 +1,4 @@ +Inline Image + +No image for you + diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 626cc7d3b0..25426a5547 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -620,7 +620,10 @@ module ActionView options.symbolize_keys! src = options[:src] = path_to_image(source) - options[:alt] = options.fetch(:alt){ File.basename(src, '.*').capitalize } + + unless src =~ /^cid:/ + options[:alt] = options.fetch(:alt){ File.basename(src, '.*').capitalize } + end if size = options.delete(:size) options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$} @@ -754,7 +757,7 @@ module ActionView end def is_uri?(path) - path =~ %r{^[-a-z]+://} + path =~ %r{^[-a-z]+://|^cid:} end # Pick an asset host for this source. Returns +nil+ if no host is set, diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index b6a6f52876..633641514e 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -404,6 +404,15 @@ class AssetTagHelperTest < ActionView::TestCase assert_equal %(<img alt="Rails" src="#{expected_path}" />), image_tag("rails.png") end + def test_image_tag_interpreting_email_cid_correctly + # An inline image has no need for an alt tag to be automatically generated from the cid: + assert_equal '<img src="cid:thi%25%25sis@acontentid" />', image_tag("cid:thi%25%25sis@acontentid") + end + + def test_image_tag_interpreting_email_adding_optional_alt_tag + assert_equal '<img alt="Image" src="cid:thi%25%25sis@acontentid" />', image_tag("cid:thi%25%25sis@acontentid", :alt => "Image") + end + def test_timebased_asset_id_with_relative_url_root @controller.config.relative_url_root = "/collaboration/hieraki" expected_time = File.stat(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).mtime.to_i.to_s diff --git a/railties/guides/source/3_0_release_notes.textile b/railties/guides/source/3_0_release_notes.textile index 75c03be87c..35a386613f 100644 --- a/railties/guides/source/3_0_release_notes.textile +++ b/railties/guides/source/3_0_release_notes.textile @@ -565,6 +565,7 @@ Action Mailer has been given a new API with TMail being replaced out with the ne * All mailers are now in <tt>app/mailers</tt> by default. * Can now send email using new API with three methods: +attachments+, +headers+ and +mail+. +* ActionMailer now has native support for inline attachments using the <tt>attachments.inline</tt> method. * Action Mailer emailing methods now return <tt>Mail::Message</tt> objects, which can then be sent the +deliver+ message to send itself. * All delivery methods are now abstracted out to the Mail gem. * The mail delivery method can accept a hash of all valid mail header fields with their value pair. diff --git a/railties/guides/source/action_mailer_basics.textile b/railties/guides/source/action_mailer_basics.textile index a2a748c749..8eb48e2751 100644 --- a/railties/guides/source/action_mailer_basics.textile +++ b/railties/guides/source/action_mailer_basics.textile @@ -211,6 +211,37 @@ attachments['filename.jpg'] = {:mime_type => 'application/x-gzip', NOTE: If you specify an encoding, Mail will assume that your content is already encoded and not try to Base64 encode it. +h5. Making Inline Attachments + +Inline attachments are now possible in ActionMailer. While previously in the pre 3.0 version of Rails, you could do inline attachments, it involved a lot of hacking and determination to pull it off. + +ActionMailer now makes inline attachments as trivial as they should be. + +* Firstly, to tell Mail to turn an attachment into an inline attachment, you just call <tt>#inline</tt> on the attachments method within your Mailer: + +<ruby> +def welcome + attachments.inline['image.jpg'] = File.read('/path/to/image.jpg') +end +</ruby> + +* Then in your view, you can just reference <tt>attachments[]</tt> as a hash and specify which attachment you want to show, calling +url+ on it and then passing the result into the <tt>image_tag</tt> method: + +<erb> +<p>Hello there, this is our image</p> + +<%= image_tag attachments['image.jpg'].url %> +</erb> + +* As this is a standard call to +image_tag+ you can pass in an options hash after the attachment url as you could for any other image: + +<erb> +<p>Hello there, this is our image</p> + +<%= image_tag attachments['image.jpg'].url, :alt => 'My Photo', + :class => 'photos' %> +</erb> + h4. Mailer Views Mailer views are located in the +app/views/name_of_mailer_class+ directory. The specific mailer view is known to the class because it's name is the same as the mailer method. So for example, in our example from above, our mailer view for the +welcome_email+ method will be in +app/views/user_mailer/welcome_email.html.erb+ for the HTML version and +welcome_email.text.erb+ for the plain text version. |