#61
Jul 23, 2007

Sending Email

This is a brief guide to sending email in Rails. See how to configure the environment, generate a mailer, create a template, and deliver the mail.
Download (11.9 MB, 7:58)
alternative download for iPod & Apple TV (9.6 MB, 7:58)

Resources

# config/environments/development.rb
config.action_mailer.raise_delivery_errors = true

# set delivery method to :smtp, :sendmail or :test
config.action_mailer.delivery_method = :smtp

# these options are only needed if you choose smtp delivery
config.action_mailer.smtp_settings = {
  :address        => 'smtp.example.com',
  :port           => 25,
  :domain         => 'www.example.com',
  :authentication => :login,
  :user_name      => 'www',
  :password       => 'secret'
}

# users_controller.rb
UserMailer.deliver_registration_confirmation(@user)

# user_mailer.rb
def registration_confirmation(user)
  recipients  user.email
  from        "webmaster@example.com"
  subject     "Thank you for Registering"
  body        :user => user
end
<!-- registration_confirmation.rhtml -->
Hi <%= @user.name %>, ...

RSS Feed for Episode Comments 44 comments

1. chineseGuy Jul 23, 2007 at 00:46

Thanks


2. Jaffet Jul 23, 2007 at 01:02

Thank you.


3. Manuel Jul 23, 2007 at 02:19

Perfect introduction and right on time! This was my task for today. Thanks!


4. Ross Jul 23, 2007 at 02:25

Fantastic. The effort spent on all of your casts are greatly appreciated.


5. Mikel Lindsaar Jul 23, 2007 at 02:42

Ryan, you are scary :) This is the third time I thought "Hmm... I need to learn about X" and then I look at iTunes and your screen cast JUST DOWNLOADED WITH THE EXACT SUBJECT I WAS GOING TO LOOK AT!!!

Freeeeeeeeeeky.... but very, very, very cool :)

Thanks again

Mikel


6. gUI Jul 23, 2007 at 06:12

Clear, simple... as always !!!

Thanks a lot for your work.


7. dave Jul 23, 2007 at 13:37

Just curious. If you sent email via SMTP - that process actually sends the mail at the time of request and doesn't cue it up for later delivery correct? So if the SMTP server you're mailing thru takes forever to answer/deliver - you're user is stuck waiting as well?


8. Ryan Bates Jul 23, 2007 at 14:05

@dave, good question. I believe ActionMailer will open a socket to the mail server right there and send the email (using net/smtp). If the mail server takes a while to respond then it might hang. I don't know for sure though. The best thing to do is try it out and see.

It would be really cool if ActionMailer had a separate queue, that way if the smtp server is down or anything it would throw it in the queue for later delivery.


9. Martin Jul 23, 2007 at 15:03

@dave, @Ryan:

I'm not familiar with ActionMailer (I'm still new to Ruby/Rails), but any sane e-mail client (ActionMailer, in this case) will throw an error if the SMTP server you're trying to connect to is unavailable.

Messages are not delivered in real time. The client (ActionMailer) will hand the message over to the SMTP server, which in turn is responsible for delivering the message. The client's involvement ends there. The SMTP server will add the e-mail to it's queue and deliver it as soon as possible. If it can't (i.e. the receiving server is unavailable) it will stop trying after some time (usually a few days) and notify the sender by e-mail.

Short story: A broken mail server won't hang your application :)


10. dave Jul 23, 2007 at 17:04

@martin
I was referring to possibility of connection timeouts and the length it would take to connect to, transfer and complete the transaction between your rails app and the SMTP server you're trying to send mail thru. If your SMTP server isn't responding quickly, your user could experience a lag time.

Where as if you went with the sendmail option for actionmailer, sendmail, postfix, whatever your MTA is would accept the email, then try to send it out for you - adding it to a background process que, freeing up your app to continue on (in theory).

I think for me the sendmail option is a better one, but then you've gotta configure your MTA yourself (at least in my case on a VPS).

I'm far from close to launching my app, so for dev's sake, I'm sticking with SMTP option for now.

Thx Ryan!


11. dudzjosh Jul 23, 2007 at 19:23

Thanks Ryan,

Awesome tip, I've been using the instance variable technique for quite awhile now :D


12. Chuck Vose Jul 23, 2007 at 19:26

@dave, @Ryan:

ActiveMailer is not asynchronous so it does hang if the smtp is busy but not if it's denying requests. The popular example is sending mass emails through ActiveMailer using Mongrels as the app server (because Mongrel has a 60 second timeout).

The way around this is to either configure smtp to queue mails (the default for most MTAs), or to use something like ar_mailer by Eric Hodel if you don't control your MTA.

http://blog.segment7.net/articles/2006/08/15/ar_mailer


13. macovsky Jul 24, 2007 at 00:34

@Ryan,

is there a way to share usual helper methods for emails' views? or to define them at one place?


14. sfty Jul 24, 2007 at 07:18

TYVM!

ActionMailer was the next thing on my TODO list also. ;)

I guess the path of learning things in Rails is quite similar for many people.

Very interesting! :D


15. dave Jul 24, 2007 at 09:33

@ryan, what might be a helpful cast would be, how to send multi-part emails in Rails. Both plain text and HTML combined in one email.

Thx!


16. dave Jul 24, 2007 at 09:36

should have read the api docs before speaking. it's all right in there :-)


17. Ryan Bates Jul 24, 2007 at 09:48

@macovsky, good question. I believe you can create your own custom helper module (helpers/foo_helper.rb) and include that using "helper :foo" in the UserMailer class. This is very similar to how you would set up custom helper modules in a controller. Untested.


18. Carl Jul 24, 2007 at 13:15

Chuck, is it Mongrel that has the 60 sec timeout or Apache? I increased the timeout on Apache (I have several tasks for my app that can take a few hundred seconds, directory crawling, etc) and Mongrel seems to keep going until the task is done (but Apache may throw a "proxy mod error" if it goes too long, which is why I increased the time). And yes, its an internal website for logging people's work, so it's okay that it can take a long time on certain tasks, those tasks don't come up that often.


19. Adam Patterson Jul 24, 2007 at 17:39

The whole time I was wondering why you weren't using instance variables for the email, like in Acts As Authenticated, but you answered at the end.. I guess AAA is a bit out of date then?

Also, one thing I like about AAA is the user_observer where you can specify something like this

  def after_create(user)
    UserNotifier.deliver_signup_notification(user)
  end

Seems like a more modular approach so you dont have to put it in multiple controllers. Any thoughts on this?


20. Ryan Bates Jul 24, 2007 at 19:10

Using the observer is a neat trick, but I can imagine it backfiring. Let's say you set up a rake task to import a bunch of users from a csv file. Well, all of those will receive an email as the User model is created. In some cases this may be what you want, but I prefer to have more control over when an email is sent. I don't want to spam someone accidentally. The act of sending an email seems more like a controller action to me.


21. Bill Davis Jul 27, 2007 at 05:48

Great screencast!

I am left wondering, however, how you can extend this to send the user to an activation link. IOW they cant login till they click the link you send them in the email.

Is this really involved?


22. Ryan Bates Jul 27, 2007 at 08:41

@Bill, I would set up an ActivationsController to do this. You can have a link in the email point to this controller and the controller can activate that account. You would need to add a unique token column to the users controller so there's some way to identify it so it can't be guessed.


23. Diego Jul 29, 2007 at 20:31

Thanks for your work Ryan

you are great


24. Tyler Jul 31, 2007 at 08:34

Is there any reason why ActionMailer wouldn't send emails in development on localhost? I don't get any error messages and the development tail returns "Sent mail:" with the message details following.


25. Ryan Bates Jul 31, 2007 at 13:37

@Tyler, It's hard to say. Did you set raise_delivery_errors to true? If you're using SMTP then check the logs on the SMTP server (if you can). If you're using sendmail then it's probably not configured properly. You may want to ask this on railsforum.com


26. Diego Aug 05, 2007 at 00:01

is there a way to send email from script/console directly?


27. Diego Aug 05, 2007 at 13:29

what is the difference with ActionMailer and UserMailer?


28. Diego Aug 05, 2007 at 19:13

Oops, just forgot the UserMailer is the class that I've created and that inherits from ActionMailer.


29. Diego Aug 05, 2007 at 19:14

Great tutorial thought, I've already sent mail from script/console :)

Keep up the great work!


30. Diego Aug 08, 2007 at 00:54

is there a way to avoid the database part, i just want to send the mail directly without saving the mail into the database, is there a way to do this?


31. Ryan Bates Aug 08, 2007 at 07:27

@Diego, yep. You can create a model object which doesn't inherit from ActiveRecord and just use that. However, validation will be quite a bit trickier.

Even if you don't need to store the data in the database, I prefer to anyway. This way I have a backup of every user input in case the email isn't delivered properly.


32. Diego Aug 18, 2007 at 00:52

yeah i think is a good idea too, thanks ryan :)


33. Daniel Sep 15, 2007 at 05:11

Thanks for your source code, it saved me a lot of time! Well, if I want to use the code snippet in production, I only have to copy the code into the production.rb or is the environment.rb a better place?


34. Ryan Bates Sep 15, 2007 at 08:31

You can place it in environment.rb, but it will then be shared across all environments. Likely you want to customize how the mailing is going to happen between environments so I recommend placing it in production.rb.


35. lark Feb 19, 2008 at 16:09

I am using sendmail to allow users visiting my site to send emails. This works fine with my configuration except when the recipients have a yahoo address. Yahoo seems to put my mail into the spam folder. Has anyone else encountered this?


36. Dave Mar 05, 2008 at 12:31

i think what would have been helpful after having done all this setup is to show how to test if the setup is correct via script/console.

the way this is presented, it seems to asume that you have all this work done on having users, and what i would want to do first is test if the setup was correct. are there a few commands that will get to that?

also, in some cases i have seen things defined as this:

ActionMailer::Base.smtp_settings = {
  :address => "your smtp server",
  :port => smtp-port,
  :domain => 'your domain'
}

verses the way that you did it here... is this a newer way to do setup?


37. Hari May 09, 2008 at 11:58

I have setup ActionMailer to send mails via Gmail.

Here are the settings:

config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => "587",
:domain => "example.com",
:authentication => :plain,
:user_name => "admin@example.com",
:password => "secret"
}
The "admin" username has an email account setup with a name of "Mailer
Account"

How do I set the From: header so that the user's inbox shows the name on
the account that the mail is sent from instead of the username "admin"
that shows up currently.

How do I get this to happen?

Thanks in advance


38. kino May 23, 2008 at 01:57

As is evident upon close examination, the manifold, in particular, exists in our concepts, but reason has lying before it the employment of the Antinomies.


39. John May 29, 2008 at 05:56

Dave,

You might need to associate the email you want to display with the email account you're using to authenticate.

Gmail is probably not allowing you to change your "from" because it doesn't recognize the specified email as yours.


40. Ank Jul 02, 2008 at 06:18

Hi,
  Thanks for the screencast. The problem i am facing is that in the smtp settings you can have only one setting. e.g if I sometimes want to send a mail from gmail and another time from yahoo I have to change the settings in the production.rb or development.rb. How can i configure it, so i can use both the settings of yahoo and gmail(or any other) depending on from where the user wishes to send his mail.
Thank you.


41. Ahmed Abulnasr Nov 04, 2008 at 04:02

thank you so much ...
it's GREAT :-D


42. Ben Nov 17, 2008 at 08:12

Hi,

Thanks for the tutorial.

Played around with ActionMailer and I got it to work from the console and by running script/server.

We're running passenger (mod_rails) and I can't seem to send mail with it. I'm sending via smtp.

Any suggestions?


46. Tim Dec 05, 2008 at 16:16

I'm not clear on what the user_name and pass are the user/pass TO. Can you explain?


47. jordan shoes Jan 06, 2009 at 01:33

good, thanks for your infos

Add your comment:

(SKIP THIS ONE)

(required)

(not shown)


(use pastie or gist for code)

sponsored by:
if you want to help:
required:
Get Quicktime Player