Sending Mail with Rails
Problem
You want to send an email from within your Rails application: perhaps a confirmation of an order, or notification that some action has been taken on a users behalf.
Solution
The first is to generate some mailer infrastructure. Go to the applications base directory and type this command:
./script/generate mailer Notification welcome exists app/models/ create app/views/notification exists test/unit/ create test/fixtures/notification create app/models/notification.rb create test/unit/notification_test.rb create app/views/notification/welcome.rhtml create test/fixtures/notification/welcome
We e giving the name "Notification" to the mailing center of the application; its somewhat analogous to a controller in the web interface. The mailer is set up to generate a single email, called "welcome": this is analagous to an action with a view template.
Now open app/models/notification.rb and edit it to look like this:
class Notification < ActionMailer::Base def welcome(user, sent_at=Time.now) @subject = A Friendly Welcome @recipients = user.email @from = admin@mysite.com @sent_on = sent_at @body = { :user => user, :sent_on => sent_at } attachment ext/plain do |a| a.body = File.read( ules.txt) end end end
The subject of the email is "A Friendly Welcome", and its sent to the users email address from the address "admin@mysite.com". Its got an attachment taken from the disk file rules.txt (relative to the root directory of your Rails application).
Although the file notification.rb is within the models/ directory, it acts like a controller in that each of its email messages has an associated view template. The view for the welcome email is in app/views/notification/welcome.rhtml, and it acts almost the same as the view of a normal controller.
The most important difference is that mailer views do not have access to the instance variables of the mailer. To set instance variables for mailers, you pass a hash of those variables to the body method. The keys become instance variable names and the values become their values. In notification.rb, we make two instance variables available to the welcome view, @user and @sent_on. Heres the view itself:
Hello, <%= @user.name %>, and thanks for signing up at <%= @sent_on %>. Please print out the attached set of rules and keep them in a prominent place; they help keep our community running smoothly. Be sure to pay special attention to sections II.4 ("Assignment of Intellectual Property Rights") and XIV.21.a ("Dispute Resolution Through Ritual Combat").
To send the welcome email from your Rails application, add the following code to either a controller, a model, or an observer:
Notification.deliver_welcome(user)
Here, the user variable can be any object that implements #name and #email, the two methods called in the welcome method and in the template.
Discussion
You never call the Notification#welcome method directly. In fact, Notification#welcome is not even available, since its an instance method, and you never instantiate a Notification object directly. The ActionMailer::Base class defines a method_missing implementation that looks at all calls to undefined class methods. This is why you call deliver_welcome even though you never defined it.
The welcome.rhtml template given above generates plaintext email. To send HTML emails, simply add the following code to Notification#welcome:
content_type ext/html
Now your templates can generate HTML; email clients will recognize the format of the email and render it appropriately.
Sometimes youll want more control over the delivery processfor example, when you e unit-testing your ActionMailer classes. Instead of calling deliver_welcome to send out an email, you can call create_welcome to get the email as a Ruby object. These "create" methods return TMail objects, which you can examine or manipulate as necessary.
If your local web server is incapable of sending email, you can modify environment.rb to contact a remote SMTP server:
Rails::Initializer.run do |config| config.action_mailer.server_settings = { :address => someserver.com, : user_name => uname, :password => passwd, :authentication => cram_md5 } end
See Also
- Recipe 10.8, "Responding to Calls to Undefined Methods"
- Recipe 14.5, "Sending Mail," has more on ActionMailer and SMTP settings
Категории