I have a rails 2.3 application and would like to integrate the premailer gem to it.
I found how can you do it for a rails 3.X application:
How to Integrate 'premailer' with Rails
Anyone knows how to do it for action mailer 2.3.10?
I've spent a good chunk of the last couple of days on this now and it seems there is no great solution. It is possible to render the message explicitly and then pass the result through Premailer, but it gets messy in combination with multipart emails and HTML layouts and if the template uses some other encoding than ASCII-8BIT.
In a straight HTML email without multiparts and assuming an ASCII-8BIT encoded template, this works for me:
def some_email
recipients "Reciever <reciever#example.com>"
from "Sender <sender#example.com>"
subject "Hello"
content_type "text/html"
message = render_message("some_email", { }) # second argument is a hash of locals
p.body = Premailer.new(message, with_html_string: true).to_inline_css
end
However, if the template is encoded with some other encoding than ASCII-8BIT, Premailer destroys all non-ASCII characters. There is a fix merged into the Premailer repo, but no version has been released since. Using the latest revision and calling Premailer.new(message, with_html_string: true, input_encoding: "UTF-8").to_inline_css or similar should work. The merge commit is https://github.com/alexdunae/premailer/commit/5f5cbb4ac181299a7e73d3eca11f3cf546585364.
In the case of multipart emails I haven't really gotten ActionMailer to use the correct content types internally for rendering the templates. This results in the implicit typing via template file names not working and, as a result, layouts being incorrectly applied to text versions. A workaround for this would be to explicitly use no layout for the text version, resulting in something like this (note the template names):
def some_multipart_email
recipients "Reciever <reciever#example.com>"
from "Sender <sender#example.com>"
subject "Hello"
content_type "text/html"
part "text/html" do |p|
message = render_message("some_email_html", { })
p.body = Premailer.new(message, with_html_string: true).to_inline_css
end
part "text/plain" do |p|
p.content_type = "text/plain"
p.body = render(file: "some_email_text", body: { }, layout: false)
end
end
Related
In our Rails 3.2 app we have the following set up to preview emails:
examples_controller
def registration
mail = EventMailer.registration(registration: EventRegistration.last, cache_email: false)
return render_mail(mail)
end
event_mailer.rb
def registration(options = {})
#registration = options[:registration]
#event = Event.find(#registration.event_id)
#subject = options[:subject] || 'Your Learn Registration'
return_email = mail(to: #registration.email, subject: #subject)
# the email if we got it
return_email
end
We just added a text version of the emails, so now in app/views/event_mailer we have registration.html.erb and registration.text.erb. Before adding the text version of the email users could browse to /webmail/examples/registration and view the html version of the email. After adding the text email, that is broken.
Ideas on how to fix this? I tried setting multipart to false in the examples controller, but that did not work.
Also, here is the render_mail method...
def render_mail(mail)
# send it through the inline style processing
inlined_content = InlineStyle.process(mail.body.to_s,ignore_linked_stylesheets: true)
render(:text => inlined_content, :layout => false)
end
I think it's not easy to debug all this code with just seeing some parts, so I'm going to suggest a different solution.
Some time ago I wrote a gem to preview emails (attachments and multiparts as well) in the browser: https://github.com/markets/maily
Main features:
Visual preview via browser (multiparts and attachments)
Template edition (development)
Email delivery
Flexible authorization system
Easy way to hook sample-data for emails
It's a Rails mountable (by default under /maily) engine, so you just need to install it, configure it and you'll be able to preview your email templates in your browser.
You can try to integrate Maily and you'll get a lot of things done, ping me if you have any doubt or suggestion.
I'm using responders gem, and I want to show validation errors when form is not valid. In my controller I created the interpolation_action
def interpolation_options
{ resource_errors: #project_user.errors.full_messages.join(', ') }
end
and my reponders translation file has a proper key:
project_users:
create:
notice: "Member has been added"
alert: "%{resource_errors}"
It works well and I can see validation error message, the problem is that apostrophe is changed to ASCII code.
Does Responder still require you to add the flash in your html? In that case you could do something like <%= flash[:alert].html_safe %> to enforce html on your flash message, even for the escaped characters.
I am using the rails 3.2.5 ActionMailer to send plain text mails. Given I have a mail view like this:
message_from_user.text.erb:
Hi <%= #recipient.name %>,
You got the following message from <%= #sender.name %>:
<%= #message %>
When #message is "quotes & ampersands", then the plain text mail contains "quotes & ampersands". So it seems like rails just treats this as a HTML view and escapes any html in order to prevent cross site scripting. However this is a plain text mail. The extension is .text.erb and ActionMailer detectes this and sets the MIME to text/plain. So I never want to escape any html in it.
I have quite a few mail templates in my application, they are all plain text. I would consider patching all of them to include <%=raw #message%> or <%= #message.html_safe %> bad style - not very DRY.
I tried varios work-arounds that included money patching Erubis. None of them seem to work. I am looking for some patch or config option or anything to disable escaping html for all .text.erb files.
Any help is greatly appreciated!
After some hours of debugging through the Erubis code, I found the following fix. You can just put it into config/initializers/fix_my_mails.rb. I've tested this with rails 3.2.7. It may work with other versions.
module ActionView
class Template
module Handlers
class ERB
def call(template)
if template.source.encoding_aware?
# First, convert to BINARY, so in case the encoding is
# wrong, we can still find an encoding tag
# (<%# encoding %>) inside the String using a regular
# expression
template_source = template.source.dup.force_encoding("BINARY")
erb = template_source.gsub(ENCODING_TAG, '')
encoding = $2
erb.force_encoding valid_encoding(template.source.dup, encoding)
# Always make sure we return a String in the default_internal
erb.encode!
else
erb = template.source.dup
end
self.class.erb_implementation.new(
erb,
:trim => (self.class.erb_trim_mode == "-"),
:escape => template.identifier =~ /\.text/ # only escape HTML templates
).src
end
end
end
end
end
It just disables HTML entities in every erb file containing .text in the file name.
Try
<%= #message.html_safe %>
You'd found this answer if you had used the search function. If that doesn't suit your needs, maybe check
https://rails.lighthouseapp.com/projects/8994/tickets/4858-actionmailer-is-html-escaping-ampersand-in-urls-in-plain-text-messages
If you haven't seen that yet, some options are discussed there
I'm using ActionMailer 3.0.7
According to the docs plain text emails are the default. So if I have an EnquiryNotifier mailer with a notify method then I expect that app/views/enquiry_notifier/notify.text.plain.erb will be rendered.
If I simply use mail(someparams) within the notify method then the body of the email is empty.
I read that ActionMailer is meant to scan the view directory to look for all types of templates.
However, if I specify the format within a block and do
mail(:to => 'somebody', :subject => 'something') do |format|
format.text
end
then my template notify.text.plain.erb does get rendered.
Maybe unrelated: If I don't specify the format but rename the template to notify.erb then it works but the email is sent as text/html.
Here's what seems to work for me in rails 3.0.6:
I don't specify a format at all in my mailer class, I just let it find the view automatically.
I name my view "notify.text.erb"
I use one layout for all my emails in my Notifier model (20+ emails)... however sometimes I just want to send a plain text email with no layout or html at all. I can't seem to be able to figure out how? If I try to send a plain text email i still get the layout, and all the HTML in the email.
I'm using Rails 2.3.8.
I read about this monkey patch here... but it seemed to indicate a newer version of rails had over come this? And I don't really wanna monkey patch if I can avoid one.
Rails - setting multiple layouts for a multipart email with mailer templates
layout "email" # use email.text.(html|plain).erb as the layout
def welcome_email(property)
subject 'New Signup'
recipients property.email
from 'welcome#test.com'
body :property => property
content_type "text/html"
end
def send_inquiry(inquire)
subject "#{inquire.the_subject}"
recipients inquire.ob.email
from "Test on behalf of #{inquire.name} <#{inquire.email}>"
body :inquire => inquire
content_type "text/plain"
end
I also have 2 files.
email.text.html.erb
email.text.plain.erb
It always uses text.html.erb... even if the content_type is "text/plain"
edit: Figured it out, the layouts follow a different naming scheme to the email templates. Just rename them as follows:
layout.text.html.erb => layout.html.erb
layout.text.plain.erb => layout.text.erb
I also made the mistake of manually defining the parts, if you use this:
part :content_type => 'text/plain',
:body => render_message('my_template')
Then Rails can't determine the content_type for your part and it assumes it's HTML.
After I changed those two things it worked for me!
original reply follows..
I've struggled with this question many times in the past, usually ending up with some sort of non-dry quick and dirty solution. I always thought I was the only one with this problem because Google turns up exactly nothing useful on the subject.
This time I decided to dig into Rails to figure it out but so far without much success, but maybe my findings will help someone else figure this out.
What I found was that in ActionMailer::Base the #render_message method is tasked with determining the proper content_type and should assign it to #current_template_content_type. #default_template_format then either returns the proper mime type for the layout or, if #current_template_content_type isn't set, it will default to :html.
This is what ActionMailer::Base#render_message looks like in my app (2.3.5)
def render_message(method_name, body)
if method_name.respond_to?(:content_type)
#current_template_content_type = method_name.content_type
end
render :file => method_name, :body => body
ensure
#current_template_content_type = nil
end
The trouble is that method_name appears to be a string (the name of the local view, in my case "new_password.text.html") and strings of course do not respond_to #content_type, meaning #current_template_content_type will always remain nil, and so the #default_template_format will always default to :html.
Not much closer to an actual solution, I know. The ActionMailer internals are just too opaque for me.
OK, not sure if this works, but it seems the default content_type is text/plain, so you would only need to set the content type if you want something other than text/plain.
Try this:
def send_inquiry(inquire)
subject "#{inquire.the_subject}"
recipients inquire.ob.email
from "Test on behalf of #{inquire.name} <#{inquire.email}>"
body :inquire => inquire
end
I still think you should consider this:
layout "email", :except => [:send_inquiry]
I would use the above because the plain text email does not seem to have a 'layout', only the actual content you want to send.
I found this that I think could be useful.
http://blog.blazingcloud.net/2009/11/17/simple-email-form-with-actionmailer/
He makes use of renaming the view templates for different content types.