diff options
-rw-r--r-- | actionmailer/CHANGELOG.md | 5 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/preview.rb | 50 | ||||
-rw-r--r-- | railties/test/application/mailer_previews_test.rb | 14 | ||||
-rw-r--r-- | railties/test/isolation/abstract_unit.rb | 4 |
4 files changed, 64 insertions, 9 deletions
diff --git a/actionmailer/CHANGELOG.md b/actionmailer/CHANGELOG.md index f88f2c0c86..e2285b75e8 100644 --- a/actionmailer/CHANGELOG.md +++ b/actionmailer/CHANGELOG.md @@ -1,3 +1,8 @@ +* Add support for inline images in mailer previews by using an interceptor + class to convert cid: urls in image src attributes to data urls. + + *Andrew White* + * Mailer preview now uses `url_for` to fix links to emails for apps running on a subdirectory. diff --git a/actionmailer/lib/action_mailer/preview.rb b/actionmailer/lib/action_mailer/preview.rb index 44cf6665ba..4888eac345 100644 --- a/actionmailer/lib/action_mailer/preview.rb +++ b/actionmailer/lib/action_mailer/preview.rb @@ -1,9 +1,57 @@ require 'active_support/descendants_tracker' +require 'base64' module ActionMailer module Previews #:nodoc: extend ActiveSupport::Concern + class InlineAttachments #:nodoc: + PATTERN = /src=(?:"cid:[^"]+"|'cid:[^']+')/i + + include Base64 + + attr_reader :message + + def self.previewing_email(message) + new(message).transform! + end + + def initialize(message) + @message = message + end + + def transform! + return message if html_part.blank? + + html_source.gsub!(PATTERN) do |match| + if part = find_part(match[9..-2]) + %[src="#{data_url(part)}"] + else + match + end + end + + message + end + + private + def html_part + @html_part ||= message.html_part + end + + def html_source + html_part.body.raw_source + end + + def data_url(part) + "data:#{part.mime_type};base64,#{urlsafe_encode64(part.body.raw_source)}" + end + + def find_part(cid) + message.all_parts.find{ |p| p.attachment? && p.cid == cid } + end + end + included do # Set the location of mailer previews through app configuration: # @@ -21,7 +69,7 @@ module ActionMailer # :nodoc: mattr_accessor :preview_interceptors, instance_writer: false - self.preview_interceptors = [] + self.preview_interceptors = [ActionMailer::Previews::InlineAttachments] end module ClassMethods diff --git a/railties/test/application/mailer_previews_test.rb b/railties/test/application/mailer_previews_test.rb index e727509610..3c9de0115f 100644 --- a/railties/test/application/mailer_previews_test.rb +++ b/railties/test/application/mailer_previews_test.rb @@ -487,13 +487,14 @@ module ApplicationTests end test "plain text mailer preview with attachment" do - image_file "pixel.png", "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEWzIioc\na/JlAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==" + image_file "pixel.png", "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEWzIioca_JlAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJgggo=" mailer 'notifier', <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" def foo + attachments['pixel.png'] = File.read("#{app_path}/public/images/pixel.png", mode: 'rb') mail to: "to@example.org" end end @@ -523,14 +524,14 @@ module ApplicationTests end test "multipart mailer preview with attachment" do - image_file "pixel.png", "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEWzIioc\na/JlAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==" + image_file "pixel.png", "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEWzIioca_JlAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJgggo=" mailer 'notifier', <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" def foo - attachments['pixel.png'] = File.read("#{app_path}/public/images/pixel.png") + attachments['pixel.png'] = File.read("#{app_path}/public/images/pixel.png", mode: 'rb') mail to: "to@example.org" end end @@ -568,14 +569,14 @@ module ApplicationTests end test "multipart mailer preview with inline attachment" do - image_file "pixel.png", "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEWzIioc\na/JlAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==" + image_file "pixel.png", "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEWzIioca_JlAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJgggo=" mailer 'notifier', <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" def foo - attachments['pixel.png'] = File.read("#{app_path}/public/images/pixel.png") + attachments['pixel.png'] = File.read("#{app_path}/public/images/pixel.png", mode: 'rb') mail to: "to@example.org" end end @@ -611,6 +612,7 @@ module ApplicationTests get "/rails/mailers/notifier/foo?part=text/html" assert_equal 200, last_response.status assert_match %r[<p>Hello, World!</p>], last_response.body + assert_match %r[src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEWzIioca_JlAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJgggo="], last_response.body end test "multipart mailer preview with attached email" do @@ -693,7 +695,7 @@ module ApplicationTests end def image_file(name, contents) - app_file("public/images/#{name}", Base64.decode64(contents)) + app_file("public/images/#{name}", Base64.urlsafe_decode64(contents), 'wb') end end end diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index 4509797da1..65d8a55421 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -270,9 +270,9 @@ module TestHelpers File.open(file, "w+") { |f| f.puts contents } end - def app_file(path, contents) + def app_file(path, contents, mode = 'w') FileUtils.mkdir_p File.dirname("#{app_path}/#{path}") - File.open("#{app_path}/#{path}", 'w') do |f| + File.open("#{app_path}/#{path}", mode) do |f| f.puts contents end end |