ActionMailer - built-in escaping of From and To fields

85 views
Skip to first unread message

Damian Nowak

unread,
Dec 6, 2015, 2:08:28 AM12/6/15
to Ruby on Rails: Core
Hi,

There's a very popular question on Stack Overflow - how to specify a sender in a "MyCompany <in...@mycompany.com>" format? Well, the answer is to specify it exactly like that, no brainer. However, the accepted answer (91 votes) suggests this: @recipients   = "\"#{user.name}\" <#{user.email}>". This is totally wrong. A better answer (150 votes) suggests this: 

require 'mail'
address = Mail::Address.new user.email
address.display_name = user.name
address.format

This is the right answer - but it doesn't feel the Rails way of doing things. In ERB/Slim templates, we say <%= user.email %> or = user.email, and we know everything will be escaped and not interpreted as HTML. I think ActionMailer could also take care about e-mail escaping. Example:

# Before:
class BillingMailer < ApplicationMailer
require 'mail'
address = Mail::Address.new "billing@#{Setting.panel_domain}"
address.display_name = "#{Setting.title} Billing"

default template_path: 'mailers/billing',
from: address.format

# After:
class BillingMailer < ApplicationMailer
default template_path: 'mailers/billing',
from_name: "#{Setting.title} Billing",
from_email: "billing@#{Setting.panel_domain}"

Does it make sense? Is it something that Rails community would find useful? Would this be accepted to Rails if I contributed the code?

Many thanks,
-Damian Nowak

Benjamin Fleischer

unread,
Dec 6, 2015, 11:32:33 AM12/6/15
to Ruby on Rails: Core
I think this is an example of stackoverflow-driven development.  Unless I misunderstand you, the answer you seek is already in the Rails guides http://guides.rubyonrails.org/action_mailer_basics.html#sending-email-with-name

I added this link to the stackoverflow question.  Generally, any question from 2009 should be ignored.

2.3.4 Sending Email With Name

Sometimes you wish to show the name of the person instead of just their email address when they receive the email. The trick to doing that is to format the email address in the format "Full Name <email>".

def welcome_email(user)
  @user = user
  email_with_name = %("#{@user.name}" <#{@user.email}>)
  mail(to: email_with_name, subject: 'Welcome to My Awesome Site')
end

Damian Nowak

unread,
Dec 6, 2015, 6:56:39 PM12/6/15
to rubyonra...@googlegroups.com
Hi Benjamin, thanks for your answer.

IYou misunderstood me. I'm stating that the current Rails way of doing that is error prone and subject to encoding errors and even injection. My reference to StackOverflow is to show it's something that a lot of developers face every day, the accepted answer is wrong, and - this is disturbing - the official guides seem to endorse the wrong way of doing that.

The code you pasted right from the docs is also wrong as it suggests to perform an unsafe operation no different to suggesting to use <%= user.name.html_safe %> and not <%= user.name %>). It's just like one of the StackOverflow answers that I described as "wrong". The only safe way is to use Mail::Address#format. Just imagine what happens if user.name contains a double-quote. Answer: no e-mail gets delivered as From field doesn't follow the RFC. The worst-case scenario is when user.name is  Nowak" <bl...@nowak.com>, "original. This is like SQL injection, but e-mail From injection.

The trick to doing that is to format the email address in the format "Full Name <email>" but you should never put user input to full name or e-mail (e.g. try #{user.email}). Everything has to be correctly encoded with an appropriate encoder to prevent broken encoding or injection.

Talk is cheap. Here's a demo of a successful injection:
class AdminMailer < ActionMailer::Base
default from: 'te...@nowaker.net'
 
def welcome_email(user)
@user = user
    email_with_name = %("#{@user.name}" <#{@user.email}>) # EXACT COPY-PASTE FROM DOCS
    mail(to: email_with_name, subject: 'Welcome to My Awesome Site')
end
end

class TestUser
attr_accessor :email
attr_accessor :name
end

user = TestUser.new
user.name = 'Nowak" <spam+INJECTED+CO...@nowaker.net>, "original'
user.email = 'spam+O...@nowaker.net'


email = AdminMailer.welcome_email(user)
What will this return?
# => #<Mail::Message:71665960, Multipart: false, Headers: <From: te...@nowaker.net>, <To: "Nowak" <spam+INJECTED+CO...@nowaker.net>, "original" <spam+O...@nowaker.net>>, <Subject: Welcome to My Awesome Site>, <Mime-Version: 1.0>, <Content-Type: text/html>> 
Let's deliver it.



Does that make sense now?​

Thanks
Damian Nowak


--
You received this message because you are subscribed to a topic in the Google Groups "Ruby on Rails: Core" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/rubyonrails-core/Fyjf-o7KTtQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to rubyonrails-co...@googlegroups.com.
To post to this group, send email to rubyonra...@googlegroups.com.
Visit this group at http://groups.google.com/group/rubyonrails-core.
For more options, visit https://groups.google.com/d/optout.

Rodrigo Rosenfeld Rosas

unread,
Dec 8, 2015, 8:36:34 AM12/8/15
to rubyonra...@googlegroups.com
May I suggest you something in an attempt to try to make the
communication more efficient?

This is how I'd write your request in a shorter way:

Currently, Rails recommends in its guide to interpolate the name when
sending e-mails with names:

http://guides.rubyonrails.org/action_mailer_basics.html#sending-email-with-name

email_with_name = %("#{@user.name}" <#{@user.email}>)

This approach is fragile because the interpolated value is not escaped,
which could break the code or deliver to multiple recipients if
exploited properly.

I'd like to suggest the Rails core team to provide a safer way to send
e-mails to named recipients in a safer way.

--

StackOverflow and the excess of formatting will probably make lots of
subscribers to this list simply skip this thread... Anyway, this is just
a suggestion...

Best,
Rodrigo.

Damian Nowak

unread,
Dec 9, 2015, 12:53:11 PM12/9/15
to Ruby on Rails: Core
Thank you Rodrigo. I'd like to suggest the Rails core team to provide a safer way to send e-mails to named recipients in a safer way... :-)

Rodrigo Rosenfeld Rosas

unread,
Dec 9, 2015, 1:49:12 PM12/9/15
to rubyonra...@googlegroups.com
I have just noticed I repeated "a safer way" in my last sentence :)
--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-co...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages