[Rails] 寄信小札記 - via ActionMailer

寄信小札記 - via ActionMailer

目的

  在很多情況下都需要透過 E-mail 的功能,而我目前是需要寄送註冊認證信給使用者,我們使用 ActionMailer 來整合 E-mail!

開發版本與環境

Ruby :v2.3.0
Rails:v4.2.5
IDE  :Cloud 9

筆記

1. Devise 設定

  這邊我們只講寄信時,devise 需注意的設定,最簡單的方式,就是開啟 Devise::Mailer

devise.rb
1
2
3
4
config.mailer_sender = 'yourname <[email protected]>'
 # 設定 mailer_sender 會顯示在寄件人 (任何格式都可,但這種格式較不會被當作垃圾信件處理)
config.mailer = 'Devise::Mailer'
 # 將註解拿掉後,就會由 devise 預設的 Mailer 寄信 (從 Devise::Mailer 作 deliver 調用 ActionMailer)

2. ActionMailer 設定

development.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
config.action_mailer.raise_delivery_errors = false
 # rails_delivery_errors 設定為 false 可讓寄信時的錯誤被忽略,如果要 debug 就設 true

config.action_mailer.default_url_options = { host: 'http://localhost:3000' }
 # 這邊填入的網址須要注意一下,他必須是絕對網址,且會被預設為 mail 中的 resource link
 # 像我是用 devise 寄發驗證信,所以 confirmation_url(@resource, confirmation_token: @token)
 # 中的 @resource 就會是 http://localhost:3000

config.action_mailer.delivery_method = :smtp
 # delivery_method 有三種寄信方式 :test、:sendmail 和 :smtp
 # sendmail 須搭配 server 的 /user/bin/sendmail application
 # 而這邊我是透過 mailgun(and gmail) 的 smtp 協定作寄信

config.action_mailer.smtp_settings = {
  :address => "smtp.gmail.com",
 :port => "587",
:domain => "yourdomain.com",
:authentication => "plain",
:user_name => "[email protected]",
:password => "yourpassword",
:enable_starttls_auto => true
}

  其實一般來說,我們不會將 smtp_settings 寫在程式碼裡,而是拆成另一個設定檔,便於管理在不同狀態下的設定:

config/email.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
development:
address: "smtp.gmail.com"
port: "587"
domain: <%=ENV['DOMAIN']%>
authentication: "plain"
user_name: <%=ENV['GMAIL_USERNAME']%>
password: <%=ENV['GMAIL_PASSWORD']%>
enable_starttls_auto: true
production:
address: "smtp.mailgun.org"
port: "587"
domain: <%=ENV['DOMAIN']%>
authentication: "plain"
user_name: <%=ENV['MAILGUN_USERNAME']%>
password: <%=ENV['MAILGUN_PASSWORD']%>
enable_starttls_auto: true

註:cloud 9 中,多數 port 預設是 blocked,但依我自己的測試, mailgun 可透過 2525、587 來寄出信件,而 gmail 只能由 587 寄信。

  smtp_settings 的部分就可以修改成:

1
2
3
config.action_mailer.smtp_settings = config_for(:email).symbolize_keys
 # config_for 會讀取 config 目錄下的 YAML 設定檔,由於 smtp_settings 需帶入 Symbol key
 # 所以透過 .symbolize_keys 將 Hash 中的 String key 轉成 Symbol key

3. 關於 email.yml

  這邊來聊聊上面的 email.yml。

  ROR 環境預設有三個,developmentproductiontest,一般 rails server 開啟環境預設是 development,我們可以透過 -e 來變更啟動環境,例如 rails s -e test

  範例 email.yml 中,則表示:
    development 時,使用 gmail 寄信。
    production 時,使用 mailgun 寄信。

  在帳號(user_name)及密碼(password)這邊需要注意的是,如果你是將密碼寫死在設定中,記得一定要將 email.yml 加到 .gitignore 中,避免上傳到 github 自曝帳密;比較好的方法是使用 RAILS_ENV 來取得環境設的變數,由於是寫在 yaml 中,所以我們寫成 <%=ENV['GMAIL_USERNAME']%>,如果是寫在 .rb 中,則使用 ENV['GMAIL_USERNAME'] 即可。這樣我們就可以透過環境設的值作設定。

4. 設定 RAILS_ENV 變數

  • 在 Ubuntu 下,可以編輯 ~/.bashrc 並加入以下作環境變數的設定 (在 Mac 下,則編輯 ~/.profile):
    1
      export GMAIL_USERNAME="[email protected]"

  以此類推,自行添加。

  • Heroku 的話,可直接在 Settings > Config Variables 中添加,或用以下指令作設定:

    1
      heroku config:add GMAIL_USERNAME="[email protected]"
  • Cloud 9 的話,在 Runner 中有 ENV 可直接添加,或用 Ubuntu 的方式添加亦可 (因為 c9 的 ROR 環境是 Ubuntu )
    c9env.png

5. Gmail 密碼問題

  其實上述四個步驟後,就可以成功的寄出信件,但還是補充一下關於 gmail 有可能寄不出信的設定問題。
  請先到 gmail 中作安全性設定,並取得密碼: 設定安全性二階段驗證應用程式密碼
  而取得的應用程式密碼就是要填入的密碼囉!

後記

  一開始我是想用 sendgrid 來作 smtp 送信,但真的試不出來也不知道什麼問題,有興趣的人可看這篇文章,雖然是阿本仔寫的,但也是很清楚明瞭!

That’s it, DONE!

【參考資料】