116

Is there a way to specify email AND name for sender and recipient info when using ActionMailer?

Typically you'd do:

@recipients   = "#{user.email}"
@from         = "info@mycompany.com"
@subject      = "Hi"
@content_type = "text/html"

But, I want to specify name as well-- MyCompany <info@mycompany.com>, John Doe <john.doe@mycompany>.

Is there a way to do that?

Grnbeagle
  • 1,751
  • 2
  • 16
  • 26
  • The Rails guides has an example of how to do this: http://guides.rubyonrails.org/action_mailer_basics.html#sending-email-with-name also see another answer in this question http://stackoverflow.com/a/8106387/879854 – BF4 Dec 06 '15 at 16:30

7 Answers7

245

If you are taking user input for name and email, then unless you very carefully validate or escape the name and email, you can end up with an invalid From header by simply concatenating strings. Here is a safe way:

require 'mail'
address = Mail::Address.new email # ex: "john@example.com"
address.display_name = name.dup   # ex: "John Doe"
# Set the From or Reply-To header to the following:
address.format # returns "John Doe <john@example.com>"
Jonathan Allard
  • 18,429
  • 11
  • 54
  • 75
James McKinney
  • 2,831
  • 1
  • 18
  • 8
  • 1
    Thank you so much! I figured there was a better way than string concat, but using `Mail::Address` isn't clear in any of the documentation I read. – Tim Morgan Nov 30 '11 at 19:04
  • 10
    `address.display_name` appears to mutate the string encoding in some cases, so if you plan on using `name` later on, e.g. in rails mailer views, do `address.display_name = name.dup` – Eero Nov 01 '13 at 11:52
  • 7
    It looks like the Mail gem now dupes the string passed in, so `name.dup` doesn't seem necessary anymore. [Source](https://github.com/mikel/mail/blob/master/lib/mail/elements/address.rb#L96) reads: `@display_name = str.nil? ? nil : str.dup` – philoye Sep 07 '16 at 04:38
  • This even works in the Devise initializer: `config.mailer_sender = Proc.new { address = Mail::Address.new... }` – Cimm Apr 29 '20 at 14:49
97
@recipients   = "\"#{user.name}\" <#{user.email}>"
@from         = "\"MyCompany\" <info@mycompany.com>"
Eduardo Scoz
  • 24,653
  • 6
  • 47
  • 62
  • what if user.name had a `"` or some other illegal character in it? – William Denniss Dec 06 '11 at 13:08
  • it'll still work fine, @WilliamDenniss. If you notice, the user.name is surrounded by escaped quotes, so it can be any string, including spaces and some symbols. – Eduardo Scoz Dec 06 '11 at 14:09
  • 2
    I don't think so. It can't contain any non-ASCII characters for one, it can't contain the quote character itself, and there are some ASCII characters that are not permitted / not recommended in headers as well. I found that RFC2047 provides a mechanism for base64 encoding such values. – William Denniss Dec 06 '11 at 23:51
  • oh, when I read what you wrote, I saw a space, and assumed you meant a space in the name.. Yeah, you're right, non-ascii chars should be encoded. – Eduardo Scoz Dec 07 '11 at 03:19
  • 11
    see my answer for a way to do this that properly encodes strings. – James McKinney Feb 09 '12 at 06:56
  • 8
    This was helpful! FYI, if you're trying to test this, you will need to look at @email.header['From'].to_s, not @email.from. The latter contains only the email address and not the name. – sbleon Mar 19 '12 at 18:18
  • 7
    Don't do it this way. See @JamesMcKinney's answer instead. – Matthew Ratzloff Sep 23 '12 at 01:52
  • 5
    Again, don't use this as it is unsafe. See @JamesMcKinney's answer instead. – Jake Petroules May 19 '14 at 04:58
  • Yes if we directly pass string it is leading into "501 Sender syntax error" error. @JamesMcKinney solutions sounds good. – Vijay Sali Jun 26 '15 at 09:26
  • This is a super old answer, everybody.. go with the other answer please. – Eduardo Scoz Feb 04 '16 at 19:52
44

In rails3 I place the following in each environment. i.e. production.rb

ActionMailer::Base.default :from => "Company Name <no-reply@production-server.ca>"

Placing quotations around the company name did not work for me in Rails3.

astjohn
  • 2,922
  • 1
  • 22
  • 25
  • You can also put it directly in your mailer.rb file like this `:from => "Company Name "` if you don't have environment restrictions. – Puce May 29 '15 at 12:29
8

within Rails 2.3.3 a bug within the ActionMailer was introduced. You can see the ticket over here Ticket #2340. It's resolved in 2-3-stable and master so it will be fixed in 3.x and 2.3.6.

For fixing the problem within 2.3.* you can use the code provided within the ticket comments:

module ActionMailer
  class Base
    def perform_delivery_smtp(mail)
      destinations = mail.destinations
      mail.ready_to_send
      sender = (mail['return-path'] && mail['return-path'].spec) || Array(mail.from).first

      smtp = Net::SMTP.new(smtp_settings[:address], smtp_settings[:port])
      smtp.enable_starttls_auto if smtp_settings[:enable_starttls_auto] && smtp.respond_to?(:enable_starttls_auto)
      smtp.start(smtp_settings[:domain], smtp_settings[:user_name], smtp_settings[:password],
                 smtp_settings[:authentication]) do |smtp|
        smtp.sendmail(mail.encoded, sender, destinations)
      end
    end
  end
end
anka
  • 3,817
  • 1
  • 30
  • 36
  • 2
    For anyone who has my question, "where do I put this code?" the answer is to save it as an .rb file in your [rails app root]/config/initializers directory. – JellicleCat Feb 24 '12 at 19:27
6

The version I like to use of this is

%`"#{account.full_name}" <#{account.email}>`

` << are backticks.

Update

You could also change that to

%|"#{account.full_name}" <#{account.email}>|
%\"#{account.full_name}" <#{account.email}>\
%^"#{account.full_name}" <#{account.email}>^
%["#{account.full_name}" <#{account.email}>]

Read more about string literals.

Marc
  • 2,584
  • 5
  • 33
  • 47
3

Since Rails 6.1 there is a new convenient helper method on ActionMailer::Base:

ActionMailer::Base.email_address_with_name("test@test.com", "John Test with Quotes <'")
=> "\"John Test with Quotes <'\" <test@test.com>"

Inside a Mailer, it is accessible without the class-name:

mail to: email_address_with_name(user.email, user.name), ...

Under the hood it uses the Mail::Address like in the top answer.

stwienert
  • 3,402
  • 24
  • 28
1

Another irritating aspect, at least with the new AR format, is to remember that 'default' is called on the class level. Referencing routines that are instance-only causes it to silently fail and give when you try to use it:

 NoMethodError: undefined method `new_post' for Notifier:Class

Here's what I ended up using:

def self.named_email(name,email) "\"#{name}\" <#{email}>" end
default :from => named_email(user.name, user.email)
Kevin
  • 4,225
  • 2
  • 37
  • 40