#61 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:
- mp4Full Size H.264 Video (12.5 MB)
- m4vSmaller H.264 Video (8.24 MB)
- webmFull Size VP8 Video (27.5 MB)
- ogvFull Size Theora Video (18.8 MB)
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
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?
@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.
i need that feature also!, would love an example for using rabbitmq or something like that.
@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 :)
@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!
Thanks Ryan,
Awesome tip, I've been using the instance variable technique for quite awhile now :D
@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
@Ryan,
is there a way to share usual helper methods for emails' views? or to define them at one place?
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
@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!
should have read the api docs before speaking. it's all right in there :-)
@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.
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.
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?
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.
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?
@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.
Thanks for your work Ryan
you are great
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.
@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
is there a way to send email from script/console directly?
what is the difference with ActionMailer and UserMailer?
Oops, just forgot the UserMailer is the class that I've created and that inherits from ActionMailer.
Great tutorial thought, I've already sent mail from script/console :)
Keep up the great work!
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?
@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.
yeah i think is a good idea too, thanks ryan :)
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?
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.
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?
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?
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
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.
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.
thank you so much ...
it's GREAT :-D
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?
I'm not clear on what the user_name and pass are the user/pass TO. Can you explain?
Is it possible to set keys in the hash: config.action_mailer.smtp_settings
dynamically? I'd like to set the :user_name just before an email is sent. Can that be done?
Thanks.
I'd be interested in learning how to set the email settings dynamically too.
Is there is any update on the comment number 48, even I want to change the mail configuration at runtime.
Hey Ryan,
Thanks for another great podcast. I was successful setting up a mailer on my user model, but when I tried to apply my learning to set up a mailer on another model I got stuck.
My problem: the Feedback model data isn't getting passed to the view, resulting in a nil error.
Would you have a look at my code and tell me if you see anything I'm missing?"
http://pastie.org/517714
Is anyone of you able to send a email contending html, plain and attachment? (all 3 parts in 1 email)
and if so, how?
i tried this example but gave me error like
530 5.7.0 Must issue a STARTTLS command first. g25sm12608420wag.43
please give me some solution
@pravin if your running ruby 1.8.7 you can get past the STARTTLS error put the line
:enable_starttls_auto => true,
in your ActionMailer::Base.smtp_settings hash.
good video..thx
To connect to gmail, use the plugin
http://github.com/collectiveidea/action_mailer_optional_tls
It has been updated to support Ruby 1.8.6 and 1.8.7 both.
if i dont have a domain then how to send email
Could you give a screencast on receiving email using Rails ? or could you point me to a good resource on the web where I could get this information. Thanks.
Thanks... I was missing deliver_ in front of method calls.
I need to tell how create this UserController is just :
rails g scaffold user name:string email:string or have any way ?