Email 寄送是現在網站是必備功能,註冊時寄,週年慶寄,雙11寄,心情好吃飽飯後寄。無怪雖然各種網路行銷,FB,GA,GTM,Line@... 一直推陳出新,Email 行銷依然活躍在舞台上。
使用 Rails 寄Email是很簡單的任務,不用額外安裝Gem,只要透過原生的ApplicationMailer
就可以辦到。
假設信都是從電商平台的後台設定並寄出的,我要產生一個AdminMailer
class專門用來寄信,使用 Rails 內建的產生器g mailer
,建立寄信功能需要的基本架構:
bin/rails g mailer Admin
# => 產生四個檔案或資料夾:
create app/mailers/admin_mailer.rb
invoke erb
create app/views/admin_mailer
invoke test_unit
create test/mailers/admin_mailer_test.rb
create test/mailers/previews/admin_mailer_preview.rb
先不看test_unit
(測試),來看:app/mailers/admin_mailer.rb
class AdminMailer < ApplicationMailer
end
g mailer
後面的參數首字大寫加上Mailer
就成為AdminMailer
class,它繼承自ApplicationMailer
。ApplicationMailer
的內容就在旁邊的檔案app/mailers/application_mailer.rb
裡:
class ApplicationMailer < ActionMailer::Base
default from: 'from@example.com'
layout 'mailer'
end
default
:設定寄件人,預設是from@example.com
,我修改成
default from: 'max@example.com'
layout 'mailer'
則是說email
用的樣板,使用 app/views/layouts/mailer.html.erb
,內容如下:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
/* Email styles need to be inline */
</style>
</head>
<body>
<%= yield %>
</body>
</html>
有沒有發現跟平常的view layout
很像,然後剛才的AdminMailer
結構又跟controller
很像。可以說 Mailer 和 Controller 非常類似。方法都叫做"動作",用 View 來 render 信件內容。但 Controller 通常是產生 HTML 回給客戶端;然而 Mailer 則是建立透過 email 寄出的信件(message)。
內容 | Controller | Mailer |
---|---|---|
類別 | UsersController | AdminMailer |
父類別 | ApplicationController | ApplicationMailer |
檔案位置 | app/contollers/users_controller.rb | app/mailers/admin_mailer.rb |
Layout | app/views/layouts/application.html.erb | app/views/layouts/mailer.html.erb |
View | app/views/users/*.erb | /app/views/admin_mailer/*.erb |
再來跟平常對待controller
一樣,定義AdminMailer
的action:notify_customer
。我接收了product
實體,並且附加了一個檔案,最後用mail
寄出email。
class AdminMailer < ApplicationMailer
def notify_customer(product)
@product = product
attachments['Ruby 考試.jpg'] = File.read('public/Ruby 考試.jpg')
mail(to: 'hchs200771@gmail.com', subject: '寄信測試')
end
end
mail
這個動作有幾個參數可以使用
如果想要附加檔案,也只要像我這樣把檔名作為attachments
的key,內容用之前教的File.read(path)
把內容讀取出來放進attachments就可以了。
信件內容可以用body
參數,ex.
mail(to: 'a@b.com', body: "<html><body>Hi there</body></html>")
但這方法不適合複雜的文件內容,我推薦像MVC裡面的view
一樣,新增跟剛才AdminMailer
的 acion
同名的notify_customer.html.erb
的檔案,放在app/views/admin_mailer
資料夾底下。
新增app/views/admin_mailer/notify_customer.html.erb
成功之後,就可以開始加入信件內容。
<h1>您好,</h1>
<p>您的購買明細如下:
<% @products.each do |product|%>
<ul>
<li>商品名稱:<%= product.title %></li>
<li>商品價格:<%= product.price %></li>
</ul>
<% end %>
</p>
<p>Max Ithome 敬上</p>
我想在訂單建立成功時,寄信給客戶
可以在Order
Model 的after_create
callback來執行
編輯app/models/order.rb
:
class Order < ApplicationRecord
after_create { AdminMailer.notify_customer(products).deliver_now }
has_many :products
end
1.剛才宣告notify_customer
是實體方法
,但是ApplicationMailer
會自動把它轉換成類別方法
。
2.AdminMailer.notify_customer(products)
還要使用deliver_now
才真的把信寄出去
到此算告一段落了,嘗試在console建立第一筆訂單
Order.create(name: '#1', products: Product.all)
# Server就開始寄信了
Rendering admin_mailer/notify_customer.html.erb within layouts/mailer
Rendered admin_mailer/notify_customer.html.erb within layouts/mailer (0.1ms)
AdminMailer#notify_customer: processed outbound mail in 21.4ms
不過現在也只是在本地端看server印出信件內容自嗨,還沒辦法真正寄email到信箱。
使用mailgun提供的第三方寄信服務,一個月有一萬封的額度。
步驟很簡單:
1.先註冊帳號
2.到domain 去,選擇SMTP
可以看到port
,Username
,Default password
,SMTP hostname
把這些資料填入config/environments/development.rb
就可以了
# 加上這段 SMTP 設定
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'smtp.mailgun.org',
port: 587,
domain: 'facebook.com',
user_name: 'postmaster@sandbox17c.....599c.mailgun.org',
password: '9d3ea4fd107b1f.....00bc6',
authentication: 'plain',
enable_starttls_auto: true
}
domain只要是合法的url都可以,這裡我是借用facebook.com
最後在console建立一個訂單
Order.create!(name: '#2', products: Product.all)
成功了⁽⁽٩(๑˃̶͈̀ ᗨ ˂̶͈́)۶⁾⁾