Daniel Lawton
Daniel Lawton

Reputation: 466

Rails Action Mailer not showing body with layout

I've recently set up a few mailers and I am trying to get a layout across all mailers. This has been done by creating an ApplicationMailer.rb which contains this:

class Application < ActionMailer::Base
    layout 'mailer'
end

I have a mailer.html.erb file in app/views/layouts and the mailer.text.erb in the same place.

mailer.html.erb:

<!DOCTYPE HTML>
<HTML lang="en">
<head>
</head>
<body>
    <%= yield %>
    <hr>
    <footer>
        Message sent from "xxx"
    </footer>
</html>

This is working well with our PasswordMailer:

class PasswordMailer < ApplicationMailer
    def password_changed(user)
        @user = user
        mail(:to => user.email, :subject => t('mailer.email_topic_password_changed'))
    end
end

But this layout is not working with my other mailer:

class SystemImportMailer < ApplicationMailer
  def notify_email(params)
    mail(to: params[:email],
         subject: "#{t('admin.import_export.import_file')}"
         body: params[:body])
  end
end

This mailer just shows the body as usual, without including the message in the layout. If I remove the body: params[:body]) line, it shows the layout message. I'm not sure why this would be the case.

Thanks

EDIT: I also have this Mailer using a different technique of adding a body.

class ScheduleMailer < ApplicationMailer
  def send_start_email(params)
    mail(to: params[:to], subject: I18n.t('schedule.start_subject')) do |format|
      format.text do
        render :text => I18n.t('schedule.start_message', type: params[:type], key: params[:key], company: params[:company]
      end
    end
  end
end

Upvotes: 1

Views: 1473

Answers (1)

cdadityang
cdadityang

Reputation: 543

Yes, That will not work. When you say:

mail(to: params[:email],
         subject: "#{t('admin.import_export.import_file')}"
         body: params[:body])

The body parameter will replace all of your mailer layout template and thus your email content will only have params[:body] content in it. If you don't pass body paramater(like in password_mailer) it will check for views in app/views/password mailer folder and render that view to email.

So instead of using the body parameter to mail, you can create an instance variable and access that inside the notify_email.html.erb or notify_email.text.erb file.

So in your mailer file:

class SystemImportMailer < ApplicationMailer
  def notify_email(params)
    # create this variable
    @body_content = params[:body]
    mail(to: params[:email],
         subject: "#{t('admin.import_export.import_file')}")
  end
end

Then in your notify_email.html.erb or notify_email.text.erb:

<p><%= @body_content %></p>

EDIT: You didn't mention your usecase, but still your complicating things when rails makes this easy.

  1. If you want to use instance var only for text version of mail then you can create @text_only_body = params[:body], then include this @text_only_body in your send_start_email.text.erb. Dont include it in your .html.erb file Ex:

    # Mailer
    def send_start_email(params)
      @text_only_body = params[:body]
      mail(to: params[:to], subject: I18n.t('schedule.start_subject'))
    end
    
    # send_start_email.text.erb
    Hello, <%= text_only_body %>
    
  2. If you only want to send text emails, you don't want to send HTML emails, then do something this:

    def send_start_email(params)
      @text_only_body = params[:body]
      mail(to: params[:to], subject: I18n.t('schedule.start_subject')) do |format|
        format.text
      end
    end
    

Upvotes: 3

Related Questions