htmlruby-on-railserubis

Rails HTML escapes plaintext emails


So, Rails has the wonderful capability of sending plaintext emails alongside HTML emails.

You just put up a .text.erb alongside your .html.erb. I put up an application to this effect here: https://github.com/cairo140/rails-email-test. Just download and run. Visit the homepage and check the logs.

Here's the output:

Sent mail to test@test.com (19ms)
Date: Tue, 01 Nov 2011 14:48:59 -0400
From: test@test.com
To: test@test.com
Message-ID: <4eb03f1b7403b_178858111fcc060bd@Steven-Xus-Macbook-Pro.local.mail>
Subject: test
Mime-Version: 1.0
Content-Type: multipart/alternative;
 boundary="--==_mimepart_4eb03f1b708ce_178858111fcc057a4";
 charset=UTF-8
Content-Transfer-Encoding: 7bit



----==_mimepart_4eb03f1b708ce_178858111fcc057a4
Date: Tue, 01 Nov 2011 14:48:59 -0400
Mime-Version: 1.0
Content-Type: text/plain;
 charset=UTF-8
Content-Transfer-Encoding: 7bit
Content-ID: <4eb03f1b72b72_178858111fcc058ce@Steven-Xus-Macbook-Pro.local.mail>

Unescaped: &

Escaped: &amp;

ERB: &amp;


----==_mimepart_4eb03f1b708ce_178858111fcc057a4
Date: Tue, 01 Nov 2011 14:48:59 -0400
Mime-Version: 1.0
Content-Type: text/html;
 charset=UTF-8
Content-Transfer-Encoding: 7bit
Content-ID: <4eb03f1b73784_178858111fcc05933@Steven-Xus-Macbook-Pro.local.mail>

<!doctype html>
<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <ul>
      <li>Unescaped: &</li>
      <li>Escaped: &amp;</li>
      <li>ERB: &amp;</li>
    </ul>
  </body>
</html>


----==_mimepart_4eb03f1b708ce_178858111fcc057a4--

Now, this is the text view (app/views/application_mailer/index.text.erb):

$ cat app/views/application_mailer/index.text.erb 
Unescaped: &

Escaped: &amp;

ERB: <%= "&" %>

As you can see, the resulting text email is overescaped.

Is there any way to prevent this?


Further clarification:

If you surpress the HTML email and just send the text, you get this in the email client (I'm using Gmail):

email body

As you can see, the third line is overescaped.

Obviously, you can call html_safe on every string, or raw on every ERB tag, but surely, there must be a way to get Rails/Erubis to recognize the fact that it's in a text email and escape accordingly.


Solution

  • There's a thread in rails' lighthouse discussing the problem and a monkey patch trying to fix it too. Try dropping this into initializers and give it a try.

    # fix_erubis_non_escape_sequence.rb
    module ActiveSupport
      class SafeBuffer < String
        alias safe_append= safe_concat
      end
    end
    
    module ActionView
      class Template
        module Handlers
          class Erubis < ::Erubis::Eruby
            def add_expr_escaped(src, code)
              if code =~ BLOCK_EXPR
                src << "@output_buffer.safe_append= " << code
              else
                src << "@output_buffer.safe_concat((" << code << ").to_s);"
              end
            end
          end
        end
      end
    end