aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionmailer/CHANGELOG.md5
-rw-r--r--actionmailer/lib/action_mailer/preview.rb50
-rw-r--r--railties/test/application/mailer_previews_test.rb14
-rw-r--r--railties/test/isolation/abstract_unit.rb4
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