跳至內容 跳至搜尋

Action Mailer 基礎

Action Mailer 允許您使用郵件模型和視圖從您的應用程式發送電子郵件。

郵件模型

要使用 Action Mailer,您需要建立一個郵件模型。

$ bin/rails generate mailer Notifier

生成的模型繼承自 ApplicationMailer,而 ApplicationMailer 又繼承自 ActionMailer::Base。郵件模型定義了用於生成電子郵件訊息的方法。在這些方法中,您可以設定要在郵件視圖中使用的變數、郵件本身的選項(例如 :from 地址)以及附件。

class ApplicationMailer < ActionMailer::Base
  default from: '[email protected]'
  layout 'mailer'
end

class NotifierMailer < ApplicationMailer
  default from: '[email protected]',
          return_path: '[email protected]'

  def welcome(recipient)
    @account = recipient
    mail(to: recipient.email_address_with_name,
         bcc: ["[email protected]", "Order Watcher <[email protected]>"])
  end
end

在郵件方法中,您可以使用以下方法

  • attachments[]= - 允許您以直觀的方式將附件添加到您的電子郵件中;attachments['filename.png'] = File.read('path/to/filename.png')

  • attachments.inline[]= - 允許您以與 attachments[]= 相同的方式將內嵌附件添加到您的電子郵件中

  • headers[]= - 允許您指定電子郵件中的任何標頭欄位,例如 headers['X-No-Spam'] = 'True'。請注意,多次宣告一個標頭會添加多個同名欄位。請閱讀 headers 文件以獲取更多資訊。

  • headers(hash) - 允許您在電子郵件中指定多個標頭,例如 headers({'X-No-Spam' => 'True', 'In-Reply-To' => '[email protected]'})

  • mail - 允許您指定要發送的電子郵件。

傳遞給 mail 方法的雜湊允許您指定 Mail::Message 將接受的任何標頭(任何有效的電子郵件標頭,包括可選欄位)。

如果未傳遞區塊,mail 方法將檢查您的視圖並發送與方法同名的所有視圖,因此上述操作將在 multipart/alternative 電子郵件中發送 welcome.text.erb 視圖檔案以及 welcome.html.erb 視圖檔案。

如果您只想明確地渲染某些範本,請傳遞一個區塊

mail(to: user.email) do |format|
  format.text
  format.html
end

區塊語法在提供特定於某個部分的資訊時也很有用

mail(to: user.email) do |format|
  format.text(content_transfer_encoding: "base64")
  format.html
end

甚至可以渲染特殊視圖

mail(to: user.email) do |format|
  format.text
  format.html { render "some_other_template" }
end

郵件視圖

與 Action Controller 一樣,每個郵件類別都有一個對應的視圖目錄,其中類別的每個方法都會在其中尋找与其名稱相同的範本。

要定義與郵件一起使用的範本,請在您的郵件模型中建立一個與該方法同名的 .erb 檔案。例如,在上面定義的郵件中,app/views/notifier_mailer/welcome.text.erb 的範本將用於生成電子郵件。

在郵件模型的方法中定義的變數可以在其對應的視圖中作為實例變數訪問。

預設情況下,電子郵件以純文字格式發送,因此我們的模型範例的範例視圖可能如下所示

Hi <%= @account.name %>,
Thanks for joining our service! Please check back often.

您甚至可以在這些視圖中使用 Action View 輔助方法。例如

You got a new note!
<%= truncate(@note.body, length: 25) %>

如果您需要在視圖中訪問主旨、寄件人或收件人,您可以透過訊息物件來完成

You got a new note from <%= message.from %>!
<%= truncate(@note.body, length: 25) %>

生成網址

可以使用 url_for 或命名路由在郵件視圖中生成網址。與 Action Pack 中的控制器不同,郵件實例沒有關於傳入請求的任何上下文,因此您需要提供生成網址所需的所有詳細資訊。

使用 url_for 時,您需要提供 :host:controller:action

<%= url_for(host: "example.com", controller: "welcome", action: "greeting") %>

使用命名路由時,您只需要提供 :host

<%= users_url(host: "example.com") %>

您應該使用 named_route_url 樣式(生成絕對網址),並避免使用 named_route_path 樣式(生成相對網址),因為閱讀郵件的客戶端將無法理解用於確定相對路徑的目前網址。

也可以透過在 config/application.rb 中將 :host 選項設定為組態選項來設定所有郵件中使用的預設主機。

config.action_mailer.default_url_options = { host: "example.com" }

您也可以在個別郵件上定義 default_url_options 方法,以覆蓋每個郵件的這些預設設定。

預設情況下,當 config.force_ssltrue 時,為主機生成的網址將使用 HTTPS 協定。

發送郵件

定義郵件動作和範本後,您可以傳遞您的訊息或延遲其建立和傳遞

NotifierMailer.welcome(User.first).deliver_now # sends the email
mail = NotifierMailer.welcome(User.first)      # => an ActionMailer::MessageDelivery object
mail.deliver_now                               # generates and sends the email now

ActionMailer::MessageDelivery 類別是委託的包裝器,它將呼叫您的方法來生成郵件。如果您想直接訪問委託者或 Mail::Message,您可以在 ActionMailer::MessageDelivery 物件上呼叫 message 方法。

NotifierMailer.welcome(User.first).message     # => a Mail::Message object

Action Mailer 與 Active Job 良好地整合,因此您可以在背景中生成和發送電子郵件(例如:在請求-回應週期之外,因此使用者不必等待它)

NotifierMailer.welcome(User.first).deliver_later # enqueue the email sending to Active Job

請注意,deliver_later 將從背景作業執行您的方法。

您永遠不會實例化您的郵件類別。相反,您只需呼叫您在類別本身上定義的方法即可。所有實例方法都應傳回要發送的訊息物件。

多部分電子郵件

多部分訊息也可以隱式使用,因為 Action Mailer 會自動偵測和使用多部分範本,其中每個範本都以動作的名稱命名,後跟內容類型。每個此類偵測到的範本都將作為單獨的部分添加到訊息中。

例如,如果存在以下範本

  • signup_notification.text.erb

  • signup_notification.html.erb

  • signup_notification.xml.builder

  • signup_notification.yml.erb

每個範本都將被渲染並作為單獨的部分添加到訊息中,並使用相應的內容類型。整個訊息的內容類型會自動設定為 multipart/alternative,這表示電子郵件包含同一電子郵件主體的多種不同表示形式。在動作中定義的相同實例變數會傳遞給所有電子郵件範本。

如果已將任何附件或部分添加到電子郵件中,則不會執行隱式範本渲染。這表示您必須手動將每個部分添加到電子郵件中,並將電子郵件的內容類型設定為 multipart/alternative

附件

在電子郵件中發送附件很容易

class NotifierMailer < ApplicationMailer
  def welcome(recipient)
    attachments['free_book.pdf'] = File.read('path/to/file.pdf')
    mail(to: recipient, subject: "New account information")
  end
end

這將(如果在視圖目錄中同時具有 welcome.text.erbwelcome.html.erb 範本)發送一個完整的多部分/混合電子郵件,其中包含兩個部分,第一部分是多部分/替代,其中包含文字和 HTML 電子郵件部分,第二部分是應用程式/ PDF,其中包含檔案 .pdf 書籍的 Base64 編碼副本,檔名為 free_book.pdf。

如果您需要發送沒有內容的附件,您需要為其建立一個空的視圖,或者像這樣添加一個空的正文參數

class NotifierMailer < ApplicationMailer
  def welcome(recipient)
    attachments['free_book.pdf'] = File.read('path/to/file.pdf')
    mail(to: recipient, subject: "New account information", body: "")
  end
end

您也可以使用 HTML 範本發送附件,在這種情況下,您需要像這樣添加正文、附件和自訂內容類型

class NotifierMailer < ApplicationMailer
  def welcome(recipient)
    attachments["free_book.pdf"] = File.read("path/to/file.pdf")
    mail(to: recipient,
         subject: "New account information",
         content_type: "text/html",
         body: "<html><body>Hello there</body></html>")
  end
end

內嵌附件

您也可以指定檔案應與其他 HTML 內嵌顯示。如果您想顯示公司標誌或照片,這將很有用。

class NotifierMailer < ApplicationMailer
  def welcome(recipient)
    attachments.inline['photo.png'] = File.read('path/to/photo.png')
    mail(to: recipient, subject: "Here is what we look like")
  end
end

然後,要在視圖中引用影象,您可以建立一個 welcome.html.erb 檔案,並呼叫 image_tag 傳遞您想要顯示的附件,然後在附件上呼叫 url 以獲取影象來源的相對內容 ID 路徑

<h1>Please Don't Cringe</h1>

<%= image_tag attachments['photo.png'].url -%>

由於我們使用的是 Action View 的 image_tag 方法,因此您可以傳遞您想要的任何其他選項

<h1>Please Don't Cringe</h1>

<%= image_tag attachments['photo.png'].url, alt: 'Our Photo', class: 'photo' -%>

觀察和攔截郵件

Action Mailer 提供了 Mail 觀察者和攔截器方法的鉤子。這些允許您註冊在郵件傳遞生命週期中呼叫的類別。

觀察者類別必須實作 :delivered_email(message) 方法,該方法將在發送每封電子郵件後呼叫一次。

攔截器類別必須實作 :delivering_email(message) 方法,該方法將在發送電子郵件之前呼叫,允許您在電子郵件到達傳遞代理之前對其進行修改。您的類別應直接對傳入的 Mail::Message 實例進行任何必要的修改。

預設雜湊

Action Mailer 為您的電子郵件提供了一些智慧預設值,這些預設值通常在類別定義內的預設方法中指定

class NotifierMailer < ApplicationMailer
  default sender: '[email protected]'
end

您可以傳入 Mail::Message 接受的任何標頭值。開箱即用,ActionMailer::Base 設定以下內容

  • mime_version: "1.0"

  • charset: "UTF-8"

  • content_type: "text/plain"

  • parts_order: [ "text/plain", "text/enriched", "text/html" ]

parts_ordercharset 實際上不是有效的 Mail::Message 標頭欄位,但 Action Mailer 會適當地轉譯它們並設定正確的值。

由於您可以傳入任何標頭,因此您需要將標頭作為字串引用,或者將其作為帶底線的符號傳入,以便以下操作有效

class NotifierMailer < ApplicationMailer
  default 'Content-Transfer-Encoding' => '7bit',
          content_description: 'This is a description'
end

最後,Action Mailer 也支援將 ProcLambda 物件傳遞到預設雜湊中,因此您可以定義在生成訊息時評估的方法

class NotifierMailer < ApplicationMailer
  default 'X-Special-Header' => Proc.new { my_method }, to: -> { @inviter.email_address }

  private
    def my_method
      'some complex call'
    end
end

請注意,proc/lambda 在郵件訊息生成的開始就被評估,因此如果您使用 proc 在預設雜湊中設定某些內容,然後在您的郵件方法中設定相同的內容,它將被郵件方法覆蓋。

也可以透過 config/application.rb 中的 default_options= 組態設定所有郵件中使用的這些預設選項

config.action_mailer.default_options = { from: "[email protected]" }

回呼

您可以使用 before_actionafter_action 指定回呼來配置您的訊息,並使用 before_deliverafter_deliver 來包裝傳遞過程。例如,當您想為某個郵件類別發送的所有訊息添加預設內嵌附件並記錄傳遞時

class NotifierMailer < ApplicationMailer
  before_action :add_inline_attachment!
  after_deliver :log_delivery

  def welcome
    mail
  end

  private
    def add_inline_attachment!
      attachments.inline["footer.jpg"] = File.read('/path/to/filename.jpg')
    end

    def log_delivery
      Rails.logger.info "Sent email with message id '#{message.message_id}' at #{Time.current}."
    end
end

Action Mailer 中的動作回呼是使用 AbstractController::Callbacks 實作的,因此您可以以與在繼承自 ActionController::Base 的類別中使用回呼相同的方式定義和配置回呼。

請注意,除非您有特殊原因,否則您應該在您的 Action Mailer 類別中優先使用 before_action 而不是 after_action,以便正確解析標頭。

搶救錯誤

郵件方法內的 rescue 區塊無法搶救渲染外部發生的錯誤 - 例如,背景作業中的記錄反序列化錯誤,或來自第三方郵件傳遞服務的錯誤。

要搶救在郵寄過程的任何部分發生的錯誤,請使用 rescue_from

class NotifierMailer < ApplicationMailer
  rescue_from ActiveJob::DeserializationError do
    # ...
  end

  rescue_from "SomeThirdPartyService::ApiError" do
    # ...
  end

  def notify(recipient)
    mail(to: recipient, subject: "Notification")
  end
end

預覽電子郵件

您可以透過將郵件預覽檔案添加到 ActionMailer::Base.preview_paths 來直觀地預覽您的電子郵件範本。由於大多數電子郵件都會對資料庫資料執行一些有趣的操作,因此您需要編寫一些場景來使用虛假資料載入訊息

class NotifierMailerPreview < ActionMailer::Preview
  def welcome
    NotifierMailer.welcome(User.first)
  end
end

方法必須傳回一個 Mail::Message 物件,該物件可以透過呼叫不帶額外 deliver_now / deliver_later 的郵件方法來生成。郵件預覽目錄的位置可以使用 preview_paths 選項進行配置,該選項的預設值為 test/mailers/previews

config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"

在執行的開發伺服器實例上,可以透過 https://127.0.0.1:3000/rails/mailers 訪問所有預覽的概覽。

也可以透過註冊具有 previewing_email 方法的預覽攔截器,以類似於傳遞攔截的方式攔截 預覽

class CssInlineStyler
  def self.previewing_email(message)
    # inline CSS styles
  end
end

config.action_mailer.preview_interceptors :css_inline_styler

請注意,如果攔截器需要在發送和預覽電子郵件時都運作,則需要使用 `register_interceptor` 和 `register_preview_interceptor` 進行註冊。

設定選項

這些選項在類別層級指定,例如 `ActionMailer::Base.raise_delivery_errors = true`

  • `default_options` - 您可以像上面章節一樣在類別層級以及類別內部傳遞此選項。

  • `logger` - 如果有的話,記錄器用於產生郵件運行資訊。可以設定為 `nil` 表示不記錄。兼容 Ruby 自身的 `Logger` 和 Log4r 記錄器。

  • `smtp_settings` - 允許對 `:smtp` 發送方法進行詳細設定。

    • `:address` - 允許您使用遠端郵件伺服器。只需將其從預設的「localhost」設定更改即可。

    • `:port` - 如果您的郵件伺服器沒有在端口 25 上運行,您可以更改它。

    • `:domain` - 如果您需要指定 HELO 網域,可以在這裡設定。

    • `:user_name` - 如果您的郵件伺服器需要驗證,請在此設定中設定使用者名稱。

    • `:password` - 如果您的郵件伺服器需要驗證,請在此設定中設定密碼。

    • `:authentication` - 如果您的郵件伺服器需要驗證,您需要在此處指定驗證類型。這是一個符號,可以是 `:plain`(將以 Base64 編碼方式發送密碼)、`:login`(將以 Base64 編碼方式發送密碼)或 `:cram_md5`(結合挑戰/回應機制來交換資訊,並使用加密訊息 `Digest` 5 演算法來雜湊重要資訊)。

    • `:enable_starttls` - 連線到 SMTP 伺服器時使用 STARTTLS,如果不支援則失敗。預設為 `false`。需要至少 2.7 版本的 `Mail` gem。

    • `:enable_starttls_auto` - 偵測 SMTP 伺服器中是否啟用了 STARTTLS 並開始使用它。預設為 `true`。

    • `:openssl_verify_mode` - 使用 TLS 時,您可以設定 OpenSSL 如何檢查憑證。如果您需要驗證自簽名和/或萬用字元憑證,這非常有用。您可以使用 OpenSSL 驗證常數的名稱(`'none'` 或 `'peer'`)或直接使用常數(`OpenSSL::SSL::VERIFY_NONE` 或 `OpenSSL::SSL::VERIFY_PEER`)。

    • `:ssl/:tls` 啟用 SMTP 連線以使用 SMTP/TLS(SMTPS:透過直接 TLS 連線的 SMTP)。

    • `:open_timeout` 嘗試開啟連線時等待的秒數。

    • `:read_timeout` 等待 read(2) 呼叫逾時的秒數。

  • `sendmail_settings` - 允許您覆蓋 `:sendmail` 發送方法的選項。

    • `:location` - sendmail 可執行檔的位置。預設為 `/usr/sbin/sendmail`。

    • `:arguments` - 命令列引數。預設為 `%w[ -i ]`,在發送訊息之前會自動新增 `-f sender@address`。

  • `file_settings` - 允許您覆蓋 `:file` 發送方法的選項。

    • `:location` - 將寫入電子郵件的目錄。預設為應用程式的 `tmp/mails`。

  • `raise_delivery_errors` - 如果電子郵件發送失敗是否應該引發錯誤。

  • `delivery_method` - 定義發送方法。可能的值為 `:smtp`(預設)、`:sendmail`、`:test` 和 `:file`。或者您可以提供自定義發送方法物件,例如 `MyOwnDeliveryMethodClass`。請參閱 `Mail` gem 文件,了解您需要為自定義發送代理程式實作的介面。

  • `perform_deliveries` - 決定當您在電子郵件訊息或 Action Mailer 方法上呼叫 `.deliver` 時,是否實際從 Action Mailer 發送電子郵件。預設為開啟,但可以關閉以協助功能測試。

  • `deliveries` - 使用 `delivery_method :test` 保留透過 Action Mailer 發送的所有電子郵件的陣列。最適用於單元和功能測試。

  • `delivery_job` - 與 `deliver_later` 一起使用的作業類別。郵件寄件器可以設定此選項以使用自定義發送作業。預設為 `ActionMailer::MailDeliveryJob`。

  • `deliver_later_queue_name` - `deliver_later` 與預設 `delivery_job` 使用的佇列名稱。郵件寄件器可以設定此選項以使用自定義佇列名稱。

命名空間
方法
A
C
D
E
H
M
N
R
S
U
已包含的模組

常數

PROTECTED_IVARS = AbstractController::Rendering::DEFAULT_PROTECTED_INSTANCE_VARIABLES + [:@_action_has_layout]
 

屬性

[W] mailer_name (郵件寄件器名稱)

允許設定目前郵件寄件器的名稱。

類別公開方法

controller_path()

mailer_name 的別名

default(value = nil)

透過應用程式設定設定預設值

config.action_mailer.default(from: "[email protected]")

`::default_options=` 設定別名

也被設定為別名:default_options=
# File actionmailer/lib/action_mailer/base.rb, line 582
def default(value = nil)
  self.default_params = default_params.merge(value).freeze if value
  default_params
end

default_options=(value = nil)

允許透過應用程式設定設定預設值

config.action_mailer.default_options = { from: "[email protected]" }
default 的別名

email_address_with_name(address, name)

傳回格式為「姓名 <[email protected]>」的電子郵件地址。

如果名稱是空白字串,則只傳回地址。

# File actionmailer/lib/action_mailer/base.rb, line 607
def email_address_with_name(address, name)
  Mail::Address.new.tap do |builder|
    builder.address = address
    builder.display_name = name.presence
  end.to_s
end

mailer_name()

傳回目前郵件寄件器的名稱。此方法也用作檢視查詢的路徑。如果這是匿名郵件寄件器,則此方法將傳回 `anonymous`。

也被設定為別名:controller_path
# File actionmailer/lib/action_mailer/base.rb, line 570
def mailer_name
  @mailer_name ||= anonymous? ? "anonymous" : name.underscore
end

new()

# File actionmailer/lib/action_mailer/base.rb, line 643
def initialize
  super()
  @_mail_was_called = false
  @_message = Mail.new
end

register_interceptor(interceptor)

註冊一個攔截器,它將在發送郵件之前被呼叫。可以將類別、字串或符號作為攔截器傳入。如果傳入字串或符號,它將被駝峰式大小寫化並常數化。

# File actionmailer/lib/action_mailer/base.rb, line 547
def register_interceptor(interceptor)
  Mail.register_interceptor(observer_class_for(interceptor))
end

register_interceptors(*interceptors)

註冊一個或多個攔截器,它們將在發送郵件之前被呼叫。

# File actionmailer/lib/action_mailer/base.rb, line 521
def register_interceptors(*interceptors)
  interceptors.flatten.compact.each { |interceptor| register_interceptor(interceptor) }
end

register_observer(observer)

註冊一個觀察者,它將在郵件發送時收到通知。可以將類別、字串或符號作為觀察者傳入。如果傳入字串或符號,它將被駝峰式大小寫化並常數化。

# File actionmailer/lib/action_mailer/base.rb, line 533
def register_observer(observer)
  Mail.register_observer(observer_class_for(observer))
end

register_observers(*observers)

註冊一個或多個觀察者,它們將在郵件發送時收到通知。

# File actionmailer/lib/action_mailer/base.rb, line 511
def register_observers(*observers)
  observers.flatten.compact.each { |observer| register_observer(observer) }
end

supports_path?()

電子郵件不支援相對路徑連結。

# File actionmailer/lib/action_mailer/base.rb, line 942
def self.supports_path? # :doc:
  false
end

unregister_interceptor(interceptor)

取消註冊先前註冊的攔截器。可以將類別、字串或符號作為攔截器傳入。如果傳入字串或符號,它將被駝峰式大小寫化並常數化。

# File actionmailer/lib/action_mailer/base.rb, line 554
def unregister_interceptor(interceptor)
  Mail.unregister_interceptor(observer_class_for(interceptor))
end

unregister_interceptors(*interceptors)

取消註冊一個或多個先前註冊的攔截器。

# File actionmailer/lib/action_mailer/base.rb, line 526
def unregister_interceptors(*interceptors)
  interceptors.flatten.compact.each { |interceptor| unregister_interceptor(interceptor) }
end

unregister_observer(observer)

取消註冊先前註冊的觀察者。可以將類別、字串或符號作為觀察者傳入。如果傳入字串或符號,它將會被駝峰式命名並常數化。

# File actionmailer/lib/action_mailer/base.rb, line 540
def unregister_observer(observer)
  Mail.unregister_observer(observer_class_for(observer))
end

unregister_observers(*observers)

取消註冊一個或多個先前註冊的觀察者。

# File actionmailer/lib/action_mailer/base.rb, line 516
def unregister_observers(*observers)
  observers.flatten.compact.each { |observer| unregister_observer(observer) }
end

實例公開方法

attachments()

允許您將附件添加到電子郵件,如下所示

mail.attachments['filename.jpg'] = File.read('/path/to/filename.jpg')

如果您這樣做,那麼 Mail 將會取得檔案名稱並判斷 MIME 類型。它還會設定 Content-TypeContent-DispositionContent-Transfer-Encoding,並將附件的內容以 Base64 編碼。

您也可以透過傳遞雜湊而不是字串來指定覆蓋

mail.attachments['filename.jpg'] = {mime_type: 'application/gzip',
                                    content: File.read('/path/to/filename.jpg')}

如果您想使用 Base64 以外的編碼方式,則需要傳遞編碼類型以及預先編碼的內容,因為 Mail 不知道如何解碼資料

file_content = SpecialEncode(File.read('/path/to/filename.jpg'))
mail.attachments['filename.jpg'] = {mime_type: 'application/gzip',
                                    encoding: 'SpecialEncoding',
                                    content: file_content }

您也可以搜尋特定的附件

# By Filename
mail.attachments['filename.jpg']   # => Mail::Part object or nil

# or by index
mail.attachments[0]                # => Mail::Part (first attachment)
# File actionmailer/lib/action_mailer/base.rb, line 760
def attachments
  if @_mail_was_called
    LateAttachmentsProxy.new(@_message.attachments)
  else
    @_message.attachments
  end
end

email_address_with_name(address, name)

傳回格式為「姓名 <[email protected]>」的電子郵件地址。

如果名稱是空白字串,則只傳回地址。

# File actionmailer/lib/action_mailer/base.rb, line 684
def email_address_with_name(address, name)
  self.class.email_address_with_name(address, name)
end

headers(args = nil)

允許您將隨機和不尋常的標頭傳遞給新的 Mail::Message 物件,它會將它們添加到自身中。

headers['X-Special-Domain-Specific-Header'] = "SecretValue"

您也可以將包含標頭欄位名稱和值的雜湊傳遞到標頭中,然後這些值將會設定在 Mail::Message 物件上

headers 'X-Special-Domain-Specific-Header' => "SecretValue",
        'In-Reply-To' => incoming.message_id

產生的 Mail::Message 將在其標頭中包含以下內容

X-Special-Domain-Specific-Header: SecretValue

關於取代已定義標頭的注意事項

  • 主旨

  • 寄件者

  • 寄件人

  • 收件者

  • 副本

  • 密件副本

  • 回覆地址

  • 原始日期

  • 訊息 ID

  • 參考

欄位在電子郵件標頭中只能出現一次,而其他欄位(例如 X-Anything)可以出現多次。

如果您想要取代任何已存在的標頭,請先將其設定為 nil 以重設值,否則將會為同一個標頭新增另一個欄位。

# File actionmailer/lib/action_mailer/base.rb, line 722
def headers(args = nil)
  if args
    @_message.headers(args)
  else
    @_message
  end
end

mail(headers = {}, &block)

建立訊息並渲染電子郵件範本的主要方法。呼叫此方法有兩種方式:使用程式碼區塊或不使用程式碼區塊。

它接受一個標頭雜湊。此雜湊允許您指定電子郵件訊息中最常用的標頭,這些標頭是

  • :subject - 訊息的主旨,如果省略此項,Action Mailer 將會詢問 Rails I18n 類別在 [mailer_scope, action_name] 範圍內是否有已翻譯的 :subject,或者如果缺少此項,將會翻譯 action_name 的人類可讀版本

  • :to - 訊息的目的地,可以是字串地址或地址陣列。

  • :from - 訊息的寄件人

  • :cc - 您想要在此電子郵件中副本傳送的對象,可以是字串地址或地址陣列。

  • :bcc - 您想要在此電子郵件中密件副本傳送的對象,可以是字串地址或地址陣列。

  • :reply_to - 將電子郵件的 Reply-To 標頭設定給誰。

  • :date - 電子郵件寄出的日期。

您可以使用 ::default 類別方法設定上述任何標頭(:date 除外)的預設值

class Notifier < ActionMailer::Base
  default from: '[email protected]',
          bcc: '[email protected]',
          reply_to: '[email protected]'
end

如果您需要上面未列出的其他標頭,您可以將它們作為標頭雜湊的一部分傳遞,或者使用 headers['name'] = value 方法。

:return_path 被指定為標頭時,該值將會被用作 Mail 訊息的「信封寄件人」地址。當您希望將遞送通知傳送到與 :from 中不同的地址時,設定此選項會很有用。Mail 實際上會優先使用 :return_path,其次是 :sender,最後是 :from 欄位作為「信封寄件人」值。

如果您沒有將程式碼區塊傳遞給 mail 方法,它將會使用預設的郵件名稱和呼叫它的方法名稱在檢視路徑中找到所有範本,然後它將會智慧地為每個範本建立部分,對正確的內容類型和順序進行有根據的猜測,並傳回一個完全準備好的 Mail::Message,可以呼叫 :deliver 來傳送。

例如

class Notifier < ActionMailer::Base
  default from: '[email protected]'

  def welcome
    mail(to: '[email protected]')
  end
end

將會在「app/views/notifier」中搜尋名稱為「welcome」的所有範本。如果沒有 welcome 範本存在,它將會引發 ActionView::MissingTemplate 錯誤。

但是,這些可以自訂

mail(template_path: 'notifications', template_name: 'another')

現在它將會在「app/views/notifications」中搜尋名稱為「another」的所有範本。

如果您確實傳遞了程式碼區塊,則可以渲染您選擇的特定範本

mail(to: '[email protected]') do |format|
  format.text
  format.html
end

您甚至可以直接渲染純文字,而無需使用範本

mail(to: '[email protected]') do |format|
  format.text { render plain: "Hello Mikel!" }
  format.html { render html: "<h1>Hello Mikel!</h1>".html_safe }
end

這將會渲染一封包含 text/plaintext/html 部分的 multipart/alternative 電子郵件。

程式碼區塊語法也允許您自訂部分標頭(如果需要)

mail(to: '[email protected]') do |format|
  format.text(content_transfer_encoding: "base64")
  format.html
end
# File actionmailer/lib/action_mailer/base.rb, line 869
def mail(headers = {}, &block)
  return message if @_mail_was_called && headers.blank? && !block

  # At the beginning, do not consider class default for content_type
  content_type = headers[:content_type]

  headers = apply_defaults(headers)

  # Apply charset at the beginning so all fields are properly quoted
  message.charset = charset = headers[:charset]

  # Set configure delivery behavior
  wrap_delivery_behavior!(headers[:delivery_method], headers[:delivery_method_options])

  assign_headers_to_message(message, headers)

  # Render the templates and blocks
  responses = collect_responses(headers, &block)
  @_mail_was_called = true

  create_parts_from_responses(message, responses)
  wrap_inline_attachments(message)

  # Set up content type, reapply charset and handle parts order
  message.content_type = set_content_type(message, content_type, headers[:content_type])
  message.charset      = charset

  if message.multipart?
    message.body.set_sort_order(headers[:parts_order])
    message.body.sort_parts!
  end

  message
end

mailer_name()

傳回郵件物件的名稱。

# File actionmailer/lib/action_mailer/base.rb, line 677
def mailer_name
  self.class.mailer_name
end

實例私有方法

default_i18n_subject(interpolations = {})

使用 Rails I18n 類別在 [mailer_scope, action_name] 範圍內翻譯 subject。如果它在指定的範圍內找不到 subject 的翻譯,它將會預設使用 action_name 的人類可讀版本。如果主旨有插值,您可以透過 interpolations 參數傳遞它們。

# File actionmailer/lib/action_mailer/base.rb, line 936
def default_i18n_subject(interpolations = {}) # :doc:
  mailer_scope = self.class.mailer_name.tr("/", ".")
  I18n.t(:subject, **interpolations.merge(scope: [mailer_scope, action_name], default: action_name.humanize))
end

set_content_type(m, user_content_type, class_default)

mail 使用來設定訊息的內容類型。

它將會使用指定的 user_content_type,或者如果郵件訊息有任何附件,則使用 multipart。如果附件是內嵌的,內容類型將會是「multipart/related」,否則為「multipart/mixed」。

如果沒有透過標頭傳入內容類型,並且沒有附件,或者訊息是 multipart,則使用預設內容類型。

# File actionmailer/lib/action_mailer/base.rb, line 914
def set_content_type(m, user_content_type, class_default) # :doc:
  params = m.content_type_parameters || {}
  case
  when user_content_type.present?
    user_content_type
  when m.has_attachments?
    if m.attachments.all?(&:inline?)
      ["multipart", "related", params]
    else
      ["multipart", "mixed", params]
    end
  when m.multipart?
    ["multipart", "alternative", params]
  else
    m.content_type || class_default
  end
end