ActionMailer - E-mail 发送

    举凡使用者注册认证信、忘记密码通知信、电子报、各种讯息通知,E-mail寄送都是现代网站必备的一项功能。RailsActionMailer元件提供了很方便的Email整合。

    Railsconfig/environments目录下针对不同执行环境会有不同的邮件服务器设定。在development.rb开发模式中,以下设定会忽略任何寄信的错误:

    建议可以改成 ,这样可以提早发现错误。

    寄信方式的选项包括有:test:sendmailsmtp三种可以选择。sendmail是使用服务器的/usr/bin/sendmail程式,不过因为因为不是每台服务器都有适当安装sendmail。而:test代表并不会实际寄信出去,而是存在ActionMailer::Base.deliveries阵列中方便做自动化测试。

    最推荐的方式是采用:smtp协定来实际寄信出去,例如以下是一个使用Gmail寄信的范例,请修改config/environments/development.rbconfig/environments/production.rb

    1. config.action_mailer.delivery_method = :smtp
    2. config.action_mailer.default_url_options = { host: "http://localhost:3000" }
    3. config.action_mailer.smtp_settings = {
    4. :address => "smtp.gmail.com",
    5. :port => "587",
    6. :domain => "gmail.com",
    7. :authentication => "plain",
    8. :user_name => "example@gmail.com",
    9. :password => "123456",
    10. :enable_starttls_auto => true
    11. }

    其中defaulturl_options设定是因为在_Email这个情境下,如果要在Email中放超连结,必须是绝对网址。所以我们必须设定网站的网址。

    另外实务上,我们其实并不会将帐号密码写死进程式里面,而是希望拆出来另存一个设定档。例如我们可以放到config/email.yml如下,YAML第一层是适用的Rails环境:

    1. development:
    2. address: "smtp.gmail.com"
    3. domain: "gmail.com"
    4. authentication: "plain"
    5. user_name: "example@gmail.com"
    6. password: "123456"
    7. enable_starttls_auto: true
    8. production:
    9. address: "smtp.mailgun.org"
    10. port: 587
    11. domain: "ihower.com"
    12. authentication: "plain"
    13. user_name: "postmaster@ihower.tw"
    14. password: "1234567890"
    15. enable_starttls_auto: true

    这样的话,smtp_settings就可以改成:

    建立一个Mailer寄信程式

    Controller一样,Rails也用generate指令产生Mailer类别,此类别中的一个方法就对应一个Email样板。以下是一个产生Mailer的范例:

    1. rails generate mailer UserMailer notify_comment

    如此便会产生app/mailers/user_mailer.rb档案,并包含一个notifycomment的_Action,其templateapp/views/user_mailer/notify_comment.text.erb(纯文字格式)和notify_comment.html.erb(HTML格式)。如果两种格式的样板档案都有,那么Rails会合并成一封Multiple Content TypesEmail

    让我们看看 user_mailer.rb 的程式:

    1. class UserMailer < ActionMailer::Base
    2. def notify_comment(user, comment)
    3. @comment = comment
    4. mail(:to => user.email, :subject => "New Comment")
    5. end

    其中default方法可以设定默认的寄件人。而 mail 方法可以设定收件人和邮件主旨。和View一样,@user物件变量可以在app/views/user_mailer/notify_comment.text.erbapp/views/user_mailer/notify_comment.html.erb或样板中存取到。而mail方法则还可以接受其他参数包括ccbcc

    我们可以在rails console中测试,执行UserMailer.notifycomment(user, comment).deliver_now!就会寄信出去。(这里我们假设存在一个_usercomment物件代表使用者和新留言,例如user = User.firstcomment = Comment.last)

    实务上,我们会在controller之中,例如使用者张贴留言之后寄发信件:

    如果只需要纯文字版,就砍掉app/views/user_mailer/notify_comment.html.erb这个档案,然后在app/views/user_mailer/notify_comment.text.erb纯文字格式中,可以加入以下文字跟网址:

    1. 有新留言在 <%= comments_url %>

    在 email 样本中,默认是不会加载 app/helpers 里面的 Helper 方法的,如果你要使用的话,可以在该 Mailer 类别中宣告如下:

    1. class UserMailer < ApplicationMailer
    2. helper :application # 这样会加载 app/helpers/application_helper.rb
    3. helper :users # 这样会加载 app/helpers/users_helper.rb
    4. # ...
    5. end

    开发期间我们需要常常测试预览寄出的Email内容,但是实际寄送出去又很没效率。我们可以安装letter_opener这个gem,修改Gemfile加入:

    然后将改成:letter_opener

    这样在开发模式下,就会开浏览器进行预览,而不会真的寄信出去。

    第三方寄信服务

    由于Gmail是个人用途使用,用量有限,并不适合开站做生意使用。我们实务上我们会使用第三方服务来确保Email递送的可靠性,例如:

    我们也可以套现成的 Email Responsive Template 样板,例如:

    收信

    Active Mailer也可以办到收信,但是你需要自行架设邮件服务器。因此需要这个功能的话,也会使用第三方服务,例如和MailChimp都有提供收信的Webhook服务:信寄到第三方服务,然后第三方再呼叫网站的HTTP API,这样就省去你自己架设邮件服务器的困难。