跳至内容 跳至搜索

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) %>

如果您需要在视图中访问主题、发件人或收件人,您可以通过 message 对象进行访问

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,您可以调用 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,其中包含文件。pdf 书籍的 Base64 编码副本,文件名是 free_book.pdf

如果您需要发送没有内容的附件,您需要为此创建一个空视图,或者添加一个空的 body 参数,如下所示

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 模板的附件,在这种情况下,您需要添加 body、attachments 和自定义内容类型,如下所示

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中可以访问。

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(将 Challenge/Response 机制结合起来交换信息,并使用密码 Message 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_NONEOpenSSL::SSL::VERIFY_PEER)。

    • :ssl/:tls 启用 SMTP 连接以使用 SMTP/TLS(SMTPS:通过直接 TLS 连接的 SMTP)

    • :open_timeout 尝试建立连接时等待的秒数。

    • :read_timeout 在读取(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: "[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)

返回格式为“Name <[email protected]>”的电子邮件。

如果 name 是一个空字符串,则只返回地址。

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

返回格式为“Name <[email protected]>”的电子邮件。

如果 name 是一个空字符串,则只返回地址。

# 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

这将渲染一个 multipart/alternative 电子邮件,其中包含 text/plaintext/html 部分。

块语法还允许您根据需要自定义部分标题

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/related”,否则是“multipart/mixed”。

如果通过标题没有传入内容类型,并且没有附件,或者消息是多部分的,则使用默认内容类型。

# 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