I'm currently setting up a large number of emails as part of our Rails application. I like to run them through Email on Acid to test them on as many email clients as possible. However, this presents a problem in development as the images are all hosted locally. The third party testing service can't access that without jumping through hoops to setup reverse proxies, etc.
Up until now I've deployed to a special staging server and then send the emails from there. This works, but it doesn't make for a rapid development process.
I don't actually care what the images look like while testing, just that they are present and in the right size so I can test spacing and layout.
So I created a mail interceptor to replace all of the images in the email with publicly accessible versions from Placehold.it.
Here is an example of what it looks like:
Here is the interceptor class. A couple of notes:
- Nothing happens unless the email is sent to the testing service.
- It required the Nokogiri gem.
- I wrap everything in a block without catching errors as I'd prefer broken image links to emails not sending.
- I shell out to Imagemagick's
identify
command. There are some image sizing gems I could use, but this is only used in development and a bit hacky anyway so… - Change the recipient to match your specific email address used for testing.
lib/email_on_acid_interceptor.rb
class EmailOnAcidInterceptor
def self.delivering_email(message)
return unless message.to_addrs.include?('xxxx.runme@previews.emailonacid.com')
doc = Nokogiri::HTML(message.html_part.body.to_s)
doc.css('img').each do |img|
begin
asset_path = URI.parse(img['src']).path
fingerprint = asset_path[/-([0-9a-f]{7,128})\.[^.]+\z/, 1]
asset_path.sub!("-#{fingerprint}", '')
asset_path.sub!("/assets/", '')
file_name = Rails.application.assets[asset_path].filename
ext = File.extname(file_name)
w, h = `identify -format '%w %h' #{file_name.shellescape}[0]`.split(' ')
img['src'] = "http://placehold.it/#{w}x#{h}#{ext}"
rescue
true
end
end
message.html_part.body = doc.to_s
end
end
To make this work it needs to be initialized. The choice of filename is up to you, but this seems like a reasonable solution. The important thing is to only load the interceptor in the development environment.
config/initializers/mail_interceptors.rb
if Rails.env.development?
ActionMailer::Base.register_interceptor(::EmailOnAcidInterceptor)
end
That's it. Restart your rails server and try it out.