Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rails mailer with different layouts

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       '[email protected]'
    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"

like image 832
holden Avatar asked Sep 06 '10 16:09

holden


People also ask

How do I have a mailer layout?

Just like controller views, you can also have mailer layouts. The layout name needs to be the same as your mailer, such as user_mailer.html.erb and user_mailer.text.erb to be automatically recognized by your mailer as a layout. In order to use a different file, call layout in your mailer:

What are the features of Mailer?

Mailers have: Actions, and also, associated views that appear in app/views. Instance variables that are accessible in views. The ability to utilise layouts and partials. The ability to access a params hash. This section will provide a step-by-step guide to creating a mailer and its views.

How do I get rails to render with a specific location?

You can use the :layout option to tell Rails to use a specific file as the layout for the current action: You can also tell Rails to render with no layout at all: You can use the :location option to set the HTTP Location header: Rails will automatically generate a response with the correct HTTP status code (in most cases, this is 200 OK ).

How do I add text to a rails page?

If you want Rails to put the text into the current layout, you need to add the layout: true option and use the .text.erb extension for the layout file. You can send an HTML string back to the browser by using the :html option to render: This is useful when you're rendering a small snippet of HTML code.


2 Answers

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.

like image 136
Peter Duijnstee Avatar answered Oct 19 '22 19:10

Peter Duijnstee


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.

like image 44
Mischa Avatar answered Oct 19 '22 19:10

Mischa