跳至内容 跳至搜索

Action Mailer 基础

Action Mailer 允许你使用邮件模型和视图从你的应用程序发送电子邮件。

邮件模型

要使用 Action Mailer,你需要创建一个邮件模型。

$ bin/rails generate mailer Notifier

生成的模型继承自 ApplicationMailer,而 ApplicationMailer 又继承自 ActionMailer::Base。邮件模型定义用于生成电子邮件消息的方法。在这些方法中,你可以设置要在邮件视图中使用的变量、邮件本身的选项(如 :from 地址)和附件。

class ApplicationMailer < ActionMailer::Base
  default from: 'from@example.com'
  layout 'mailer'
end

class NotifierMailer < ApplicationMailer
  default from: 'no-reply@example.com',
          return_path: 'system@example.com'

  def welcome(recipient)
    @account = recipient
    mail(to: recipient.email_address_with_name,
         bcc: ["bcc@example.com", "Order Watcher <watcher@example.com>"])
  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' => '1234@message.id'})

  • mail - 允许你指定要发送的电子邮件。

传递给邮件方法的哈希允许你指定 Mail::Message 将接受的任何标头(包括可选字段的任何有效电子邮件标头)。

如果未传递块,mail 方法将检查你的视图并发送与方法同名的所有视图,因此上述操作将发送 welcome.text.erb 视图文件以及 welcome.html.erb 视图文件,作为 multipart/alternative 电子邮件。

如果你只想显式呈现某些模板,请传递一个块

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

可以使用 url_for 或命名路由在邮件程序视图中生成 URL。与 Action Pack 中的控制器不同,邮件程序实例没有任何关于传入请求的上下文,因此您需要提供生成 URL 所需的所有详细信息。

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

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

在使用命名路由时,您只需提供 :host

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

您应该使用 named_route_url 样式(它生成绝对 URL),并避免使用 named_route_path 样式(它生成相对 URL),因为阅读邮件的客户端不会有任何当前 URL 的概念,无法从中确定相对路径。

还可以通过在 config/application.rb 中将 :host 选项设置为配置选项,为所有邮件程序设置将用于其中的默认主机。

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

您还可以在各个邮件程序上定义 default_url_options 方法,以按邮件程序覆盖这些默认设置。

默认情况下,当 config.force_ssltrue 时,为主机生成的 URL 将使用 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 模板,则将发送一个完整的 multipart/mixed 电子邮件,其中包含两个部分,第一部分是 multipart/alternative,其中包含内部的文本和 HTML 电子邮件部分,第二部分是 application/pdf,其中包含文件 file.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: 'system@example.com'
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: "no-reply@example.org" }

回调

你可以使用 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"

可以在正在运行的开发服务器实例上的 http://localhost:3000/rails/mailers 中访问所有预览的概述。

Previews 也可以通过注册具有 previewing_email 方法的预览拦截器的方式拦截,类似于传递可以被拦截的方式。

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

config.action_mailer.preview_interceptors :css_inline_styler

请注意,如果拦截器要在发送和预览电子邮件时运行,则需要使用 register_interceptorregister_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。需要 Mail gem 的至少 2.7 版本。

    • :enable_starttls_auto - 检测 SMTP 服务器中是否启用了 STARTTLS,并开始使用它。默认为 true

    • :openssl_verify_mode - 使用 TLS 时,您可以设置 OpenSSL 如何检查证书。如果您需要验证自签名和/或通配符证书,这非常有用。您可以使用 OpenSSL 验证常量('none''peer')的名称或直接使用常量(OpenSSL::SSL::VERIFY_NONEOpenSSL::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 - 保存通过 Action Mailer 发送的所有电子邮件的数组,其中 delivery_method :test。最适用于单元和功能测试。

  • 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: "no-reply@example.org")

别名为 ::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: "no-reply@example.org" }
别名为:default

email_address_with_name(address, name)

返回“姓名 <email@example.com>”格式的电子邮件。

如果姓名为空字符串,则只返回地址。

# 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 644
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

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

类私有方法

supports_path?()

电子邮件不支持相对路径链接。

# File actionmailer/lib/action_mailer/base.rb, line 943
def self.supports_path? # :doc:
  false
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 761
def attachments
  if @_mail_was_called
    LateAttachmentsProxy.new(@_message.attachments)
  else
    @_message.attachments
  end
end

email_address_with_name(address, name)

返回“姓名 <email@example.com>”格式的电子邮件。

如果姓名为空字符串,则只返回地址。

# File actionmailer/lib/action_mailer/base.rb, line 685
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 723
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: 'no-reply@test.lindsaar.net',
          bcc: 'email_logger@test.lindsaar.net',
          reply_to: 'bounces@test.lindsaar.net'
end

如果您需要上面未列出的其他标头,您可以将它们作为标头哈希的一部分传递,或使用 headers['name'] = value 方法。

:return_path 被指定为标头时,该值将用作 Mail 消息的“信封发件人”地址。当您希望将送达通知发送到与 :from 中的地址不同的地址时,设置此项非常有用。Mail 实际上会优先使用 :return_path,其次是 :sender,最后是 :from 字段作为“信封发件人”值。

如果您没有将块传递给 mail 方法,它将使用默认的邮件发送者名称和调用它的方法名称在视图路径中查找所有模板,然后它将为其中每个模板智能地创建部分,对正确的内容类型和顺序进行合理的猜测,并返回一个完全准备好的 Mail::Message,准备好调用 :deliver 以发送。

例如

class Notifier < ActionMailer::Base
  default from: 'no-reply@test.lindsaar.net'

  def welcome
    mail(to: 'mikel@test.lindsaar.net')
  end
end

将在“app/views/notifier”中查找所有名为“welcome”的模板。如果不存在欢迎模板,它将引发 ActionView::MissingTemplate 错误。

但是,可以自定义这些模板

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

现在它将在“app/views/notifications”中查找所有名为“another”的模板。

如果您确实传递了一个块,则可以呈现您选择的特定模板

mail(to: 'mikel@test.lindsaar.net') do |format|
  format.text
  format.html
end

您甚至可以直接呈现纯文本,而无需使用模板

mail(to: 'mikel@test.lindsaar.net') 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: 'mikel@test.lindsaar.net') do |format|
  format.text(content_transfer_encoding: "base64")
  format.html
end
# File actionmailer/lib/action_mailer/base.rb, line 870
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 678
def mailer_name
  self.class.mailer_name
end

实例私有方法

default_i18n_subject(interpolations = {})

使用 Rails I18n 类在 [mailer_scope, action_name] 范围内翻译 subject。如果在指定范围内找不到 subject 的翻译,它将默认为 action_name 的人性化版本。如果 subject 有插值,您可以通过 interpolations 参数传递它们。

# File actionmailer/lib/action_mailer/base.rb, line 937
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 915
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