The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
multipart emails with multipart layouts and inline images in ActionMailer

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Eric Hodel

Posts: 660
Nickname: drbrain
Registered: Mar, 2006

Eric Hodel is a long-time Rubyist and co-founder of Seattle.rb.
multipart emails with multipart layouts and inline images in ActionMailer Posted: Sep 30, 2009 1:44 PM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by Eric Hodel.
Original Post: multipart emails with multipart layouts and inline images in ActionMailer
Feed Title: Segment7
Feed URL: http://blog.segment7.net/articles.rss
Feed Description: Posts about and around Ruby, MetaRuby, ruby2c, ZenTest and work at The Robot Co-op.
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Eric Hodel
Latest Posts From Segment7

Advertisement

While ActionMailer claims to support multipart emails, that support is severely limited.

If you have a multipart/alternative email and are using layouts, multipart layouts don't work, the text/html layout will be used for the text/plain alternative part.

You also can't embed an image to use via <img src="cid:blah"> (or CSS, etc.) in the text/html section of your multipart/alternative mail. (I want the image to be controlled via the img element and styles, not plopped into the middle of my HTML section.)

While this ticket was closed due to lack of a test, the fix involves the modification of a constant which wouldn't be tested anyhow. (It seems nobody bothered to inform TMail about this problem either.)

Enough griping!

I managed to find a solution to these two problems!

To take care of the first problem I overrode initialize_template_class in my mailer class and manually set the template format for the part:

  def initialize_template_class(assigns)
    template_format = assigns.delete :template_format

    template = super

    template.template_format = template_format if template_format

    template
  end

Then wrote a render_multipart method that manually chooses the template and layout to render:

  def render_multipart(template, options)
    content_type 'multipart/alternative'

    part :content_type => 'multipart/related' do |related|
      html_options = { :template_format => :html }.merge options

      related.part :content_type => 'text/html',
                   :body => render(:file => "#{template}.text.html.haml",
                                   :layout => 'notifier_mailer.text.html',
                                   :body => html_options)

      related.part(:content_type => 'image/png',
                   :headers => { 'Content-Id' => 'site_logo.png' }) do |image|
        image.body = File.read LOGO_PATH
        image.transfer_encoding = 'base64'
        image.content_disposition = nil
      end

    end

    plain_options = { :template_format => :plain }.merge options

    part :content_type => 'text/plain',
         :body => render(:file => "#{template}.text.plain.erb",
                         :layout => 'notifier_mailer.text.plain',
                         :body => plain_options)
  end

For Apple mail to properly display a multipart/alternative mail the top-level MIME type needs to be multipart/alternative. The text/html alternative part is wrapped inside a multipart/related part that also contains the embedded image. (When viewing the mail as text/plain the image attachment doesn't appear on the attachments bar. When viewing as text/html it does, but I don't think that there's a way to hide it from the attachments bar.)

Fixing this For Good™ seems to involve teaching ActionPack's views about how to read MIME extensions (reset.text.plain.erb and reset.text.html.erb) instead of filetype extensions (show.html.erb and show.xml.erb) like what is used by ActionController's views. The ticket seems to indicate somebody's trying to figure out how to do that.

To take care of the embedding of an image in an email for use in the HTML part I removed the restriction on Content-Id for a part header from the patch to TMail:

TMail::HeaderField::FNAME_TO_CLASS.delete 'content-id'

Then set the Content-Id for the image and unset the Content-Disposition (copied from multipart_render above):

related.part(:content_type => 'image/png',
             :headers => { 'Content-Id' => 'site_logo.png' }) do |image|
  image.body = File.read LOGO_PATH
  image.transfer_encoding = 'base64'
  image.content_disposition = nil
end

Leaving the Content-Disposition as inline causes the image to show up once at the bottom of the HTML content and once where the <img> is present.

From a mailer method this is called with the explicit template name (I was too lazy to intuit from caller):

  def reset(user, password)
    recipients user.email
    from       REPLY_TO
    subject    "Password reset"

    render_multipart 'reset', :password => password, :recipient => user
  end

In app/views/layouts/notifier_mailer.text.html.haml I have the following snippet to use the site logo:

%img.logo{ :src => 'cid:site_logo.png' }

Read: multipart emails with multipart layouts and inline images in ActionMailer

Topic: Cookie-based Sessions in Sinatra Previous Topic   Next Topic Topic: Ext.ux.layout.FillContainer

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use