1 什么是 Action Mailer?
Action Mailer 允许您从 Rails 应用程序发送电子邮件。它是 Rails 框架中两个与电子邮件相关的组件之一。另一个是 Action Mailbox,它处理接收电子邮件。
Action Mailer 使用类(称为“邮件器”)和视图来创建和配置要发送的电子邮件。邮件器是继承自 ActionMailer::Base
的类。邮件器类类似于控制器类。两者都有
- 在视图中可访问的实例变量。
- 使用布局和部分的能力。
- 访问 params 哈希的能力。
app/views
中的操作和相关视图。
2 创建邮件器和视图
本节将提供使用 Action Mailer 发送电子邮件的分步指南。以下是每个步骤的详细信息。
2.1 生成邮件器
首先,您使用“邮件器”生成器来创建与邮件器相关的类
$ bin/rails generate mailer User
create app/mailers/user_mailer.rb
invoke erb
create app/views/user_mailer
invoke test_unit
create test/mailers/user_mailer_test.rb
create test/mailers/previews/user_mailer_preview.rb
与下面的 UserMailer
一样,所有生成的邮件器类都继承自 ApplicationMailer
# app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
end
ApplicationMailer
类继承自 ActionMailer::Base
,可用于定义所有邮件器共有的属性
# app/mailers/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
default from: "[email protected]"
layout "mailer"
end
如果您不想使用生成器,也可以手动将文件添加到 app/mailers
目录。确保您的类继承自 ApplicationMailer
# app/mailers/custom_mailer.rb
class CustomMailer < ApplicationMailer
end
2.2 编辑邮件器
app/mailers/user_mailer.rb
中的 UserMailer
最初没有任何方法。因此,接下来,我们向邮件器添加方法(也称为操作),这些方法将发送特定的电子邮件。
邮件器具有称为“操作”的方法,它们使用视图来构建其内容,类似于控制器。控制器生成 HTML 内容以发送回客户端,而邮件器创建要通过电子邮件传递的消息。
让我们向 UserMailer
添加一个名为 welcome_email
的方法,该方法将向用户的注册电子邮件地址发送电子邮件
class UserMailer < ApplicationMailer
default from: "[email protected]"
def welcome_email
@user = params[:user]
@url = "http://example.com/login"
mail(to: @user.email, subject: "Welcome to My Awesome Site")
end
end
邮件器中的方法名称不必以 _email
结尾。
以下是上述邮件器相关方法的简要说明
default
方法为从此邮件器发送的所有电子邮件设置默认值。在本例中,我们使用它来为此类中的所有消息设置:from
标头值。这可以在每个电子邮件的基础上被覆盖。mail
方法创建实际的电子邮件消息。我们使用它来为每个电子邮件指定:to
和:subject
等标头的值。
还有一个 headers
方法(上面未使用),它用于使用哈希或通过调用 headers[:field_name] = 'value'
来指定电子邮件标头。
可以在使用生成器时直接指定操作,例如
$ bin/rails generate mailer User welcome_email
以上将生成 UserMailer
,其中包含一个空 welcome_email
方法。
您还可以从单个邮件器类发送多封电子邮件。将相关的电子邮件分组在一起可能很方便。例如,上面的 UserMailer
可以包含 goodbye_email
(以及相应的视图)以及 welcome_email
。
2.3 创建邮件器视图
接下来,对于 welcome_email
操作,您需要在 app/views/user_mailer/
目录中创建一个名为 welcome_email.html.erb
的匹配视图。这是一个可用于欢迎电子邮件的示例 HTML 模板
<h1>Welcome to example.com, <%= @user.name %></h1>
<p>
You have successfully signed up to example.com,
your username is: <%= @user.login %>.<br>
</p>
<p>
To login to the site, just follow this link: <%= link_to 'login`, login_url %>.
</p>
<p>Thanks for joining and have a great day!</p>
以上是 <body>
标签的内容。它将被嵌入默认邮件器布局中,该布局包含 <html>
标签。有关更多信息,请参见 邮件器布局。
您还可以创建上述电子邮件的文本版本,并将其存储在 app/views/user_mailer/
目录中的 welcome_email.text.erb
中(注意 .text.erb
扩展名与 html.erb
扩展名不同)。发送两种格式被认为是最佳实践,因为在 HTML 渲染出现问题的情况下,文本版本可以作为可靠的后备。这是一个示例文本电子邮件
Welcome to example.com, <%= @user.name %>
===============================================
You have successfully signed up to example.com,
your username is: <%= @user.login %>.
To login to the site, just follow this link: <%= @url %>.
Thanks for joining and have a great day!
注意,在 HTML 和文本电子邮件模板中,您可以使用实例变量 @user
和 @url
。
现在,当您调用 mail
方法时,Action Mailer 将检测到这两个模板(文本和 HTML),并自动生成一个 multipart/alternative
电子邮件。
2.4 调用邮件器
设置好邮件器类和视图后,下一步是实际调用邮件器方法来渲染电子邮件视图(即发送电子邮件)。邮件器可以被认为是渲染视图的另一种方式。控制器操作渲染一个视图,该视图通过 HTTP 协议发送。邮件器操作渲染一个视图,并通过电子邮件协议发送。
让我们看一个使用 UserMailer
在成功创建用户时发送欢迎电子邮件的示例。
首先,让我们创建一个 User
脚手架
$ bin/rails generate scaffold user name email login
$ bin/rails db:migrate
接下来,我们编辑 UserController
中的 create
操作,以便在创建新用户时发送欢迎电子邮件。我们通过在用户成功保存后立即插入对 UserMailer.with(user: @user).welcome_email
的调用来实现这一点。
我们使用 deliver_later
将电子邮件排队以供稍后发送。这样,控制器操作将继续执行,而不会等待电子邮件发送代码运行。deliver_later
方法由 Active Job 支持。
class UsersController < ApplicationController
# ...
def create
@user = User.new(user_params)
respond_to do |format|
if @user.save
# Tell the UserMailer to send a welcome email after save
UserMailer.with(user: @user).welcome_email.deliver_later
format.html { redirect_to user_url(@user), notice: "User was successfully created." }
format.json { render :show, status: :created, location: @user }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
# ...
end
传递给 with
的任何键值对都将成为邮件器操作的 params
。例如,with(user: @user, account: @user.account)
使 params[:user]
和 params[:account]
在邮件器操作中可用。
通过上述邮件器、视图和控制器设置,如果您创建了一个新的 User
,您可以检查日志以查看是否已发送欢迎电子邮件。日志文件将显示已发送的文本和 HTML 版本,如下所示
[ActiveJob] [ActionMailer::MailDeliveryJob] [ec4b3786-b9fc-4b5e-8153-9153095e1cbf] Delivered mail [email protected] (19.9ms)
[ActiveJob] [ActionMailer::MailDeliveryJob] [ec4b3786-b9fc-4b5e-8153-9153095e1cbf] Date: Thu, 06 Jun 2024 12:43:44 -0500
From: [email protected]
To: [email protected]
Message-ID: <[email protected]>
Subject: Welcome to My Awesome Site
Mime-Version: 1.0
Content-Type: multipart/alternative;
boundary="--==_mimepart_6661f55086194_1380c7eb869259";
charset=UTF-8
Content-Transfer-Encoding: 7bit
----==_mimepart_6661f55086194_1380c7eb869259
Content-Type: text/plain;
...
----==_mimepart_6661f55086194_1380c7eb869259
Content-Type: text/html;
...
您也可以从 Rails 控制台中调用邮件器并发送电子邮件,这可能在您设置控制器操作之前很有用。以下将发送与上面相同的 welcome_email
irb> user = User.first
irb> UserMailer.with(user: user).welcome_email.deliver_later
如果您想立即发送电子邮件(例如,从 cron 作业发送),您可以调用 deliver_now
class SendWeeklySummary
def run
User.find_each do |user|
UserMailer.with(user: user).weekly_summary.deliver_now
end
end
end
类似于 UserMailer
中的 weekly_summary
方法,该方法将返回一个 ActionMailer::MessageDelivery
对象,该对象具有 deliver_now
或 deliver_later
方法,用于立即或稍后发送邮件。ActionMailer::MessageDelivery
对象是 Mail::Message
的包装器。如果您想检查、更改或对 Mail::Message
对象执行其他操作,可以使用 ActionMailer::MessageDelivery
对象的 message
方法访问它。
以下是如何在 Rails 控制台中使用 MessageDelivery
对象的示例
irb> UserMailer.with(user: user).weekly_summary
#<ActionMailer::MailDeliveryJob:0x00007f84cb0367c0
@_halted_callback_hook_called=nil,
@_scheduled_at_time=nil,
@arguments=
["UserMailer",
"welcome_email",
"deliver_now",
{:params=>
{:user=>
#<User:0x00007f84c9327198
id: 1,
name: "Bhumi",
email: "[email protected]",
login: "Bhumi",
created_at: Thu, 06 Jun 2024 17:43:44.424064000 UTC +00:00,
updated_at: Thu, 06 Jun 2024 17:43:44.424064000 UTC +00:00>},
:args=>[]}],
@exception_executions={},
@executions=0,
@job_id="07747748-59cc-4e88-812a-0d677040cd5a",
@priority=nil,
3 多部分邮件和附件
multipart
MIME 类型表示由多个组成部分组成的文档,每个组成部分都可以有其自己的 MIME 类型(例如 text/html
和 text/plain
)。multipart
类型封装了将多个文件一起发送在一个事务中,例如将多个文件附加到电子邮件。
3.1 添加附件
您可以通过将文件名和内容传递给 attachments 方法 来添加附件。Action Mailer 将自动猜测 mime_type
、设置 encoding
并创建附件。
attachments["filename.jpg"] = File.read("/path/to/filename.jpg")
当触发 mail
方法时,它将发送一封包含附件的多部分邮件,并以正确的方式嵌套,顶层为 multipart/mixed
,第一个部分为 multipart/alternative
,包含纯文本和 HTML 邮件消息。
另一种发送附件的方法是指定文件名、MIME 类型和编码头以及内容。Action Mailer 将使用您传入的设置。
encoded_content = SpecialEncode(File.read("/path/to/filename.jpg"))
attachments["filename.jpg"] = {
mime_type: "application/gzip",
encoding: "SpecialEncoding",
content: encoded_content
}
Action Mailer 将自动对附件进行 Base64 编码。如果您想要其他编码方式,可以对内容进行编码,并将编码后的内容以及编码方式作为 Hash
传递给 attachments
方法。如果您指定了编码方式,Action Mailer 将不会尝试对附件进行 Base64 编码。
3.2 创建内联附件
有时,您可能希望将附件(例如图像)内联发送,使其显示在电子邮件正文中。
要做到这一点,首先,您可以通过调用 #inline
将附件转换为内联附件。
def welcome
attachments.inline["image.jpg"] = File.read("/path/to/image.jpg")
end
然后在视图中,您可以将 attachments
作为哈希表进行引用,并指定要内联显示的文件。您可以对哈希表调用 url
并将结果传递给 image_tag
方法
<p>Hello there, this is the image you requested:</p>
<%= image_tag attachments['image.jpg'].url %>
由于这是一个对 image_tag
的标准调用,您也可以在附件 URL 之后传递一个选项哈希表。
<p>Hello there, this is our image</p>
<%= image_tag attachments['image.jpg'].url, alt: 'My Photo', class: 'photos' %>
3.3 多部分邮件
如 创建邮件视图 中所示,如果您对同一个操作有不同的模板,Action Mailer 将自动发送多部分邮件。例如,如果您有一个 UserMailer
,其中在 app/views/user_mailer
中包含 welcome_email.text.erb
和 welcome_email.html.erb
,Action Mailer 将自动发送一封包含 HTML 和文本版本的多部分邮件,作为单独的部分。
Mail gem 提供了辅助方法,用于创建用于 text/plain
和 text/html
MIME 类型 的 multipart/alternate
邮件,并且您可以手动创建任何其他类型的 MIME 邮件。
插入部分的顺序由 ActionMailer::Base.default
方法中的 :parts_order
决定。
当您使用电子邮件发送附件时,也会使用多部分邮件。
4 邮件视图和布局
Action Mailer 使用视图文件来指定要发送到电子邮件中的内容。默认情况下,邮件视图位于 app/views/name_of_mailer_class
目录中。与控制器视图类似,文件名称与邮件方法名称匹配。
邮件视图是在布局中渲染的,类似于控制器视图。邮件布局位于 app/views/layouts
中。默认布局为 mailer.html.erb
和 mailer.text.erb
。本节介绍邮件视图和布局的各种功能。
4.1 配置自定义视图路径
可以使用多种方法更改操作的默认邮件视图,如下所示。
mail
方法具有 template_path
和 template_name
选项
class UserMailer < ApplicationMailer
default from: "[email protected]"
def welcome_email
@user = params[:user]
@url = "http://example.com/login"
mail(to: @user.email,
subject: "Welcome to My Awesome Site",
template_path: "notifications",
template_name: "hello")
end
end
上面的代码配置了 mail
方法,以在 app/views/notifications
目录中查找名为 hello
的模板。您也可以为 template_path
指定路径数组,它们将按顺序被搜索。
如果您需要更多灵活性,您还可以传递一个代码块并渲染特定模板。您也可以在不使用模板文件的情况下,直接渲染纯文本。
class UserMailer < ApplicationMailer
default from: "[email protected]"
def welcome_email
@user = params[:user]
@url = "http://example.com/login"
mail(to: @user.email,
subject: "Welcome to My Awesome Site") do |format|
format.html { render "another_template" }
format.text { render plain: "hello" }
end
end
end
这将渲染 another_template.html.erb
模板作为 HTML 部分,并渲染 “hello” 作为文本部分。render 方法与 Action Controller 中使用的方法相同,因此您可以使用所有相同的选项,例如 :plain
、:inline
等。
最后,如果您需要渲染位于默认 app/views/mailer_name/
目录之外的模板,您可以使用 prepend_view_path
,如下所示
class UserMailer < ApplicationMailer
prepend_view_path "custom/path/to/mailer/view"
# This will try to load "custom/path/to/mailer/view/welcome_email" template
def welcome_email
# ...
end
end
还有一个 append_view_path
方法。
4.2 在 Action Mailer 视图中生成 URL
要向邮件添加 URL,首先需要将 host
值设置为应用程序的域名。这是因为与控制器不同,邮件实例没有关于传入请求的任何上下文信息。
您可以在 config/application.rb
中配置应用程序范围内的默认 host
config.action_mailer.default_url_options = { host: "example.com" }
配置完 host
之后,建议电子邮件视图使用包含完整 URL 的 *_url
,而不是使用包含相对 URL 的 *_path
辅助方法。由于电子邮件客户端没有 Web 请求上下文,因此 *_path
辅助方法没有用于形成完整 Web 地址的基 URL。
例如,不要使用
<%= link_to 'welcome', welcome_path %>
而是使用
<%= link_to 'welcome', welcome_url %>
通过使用完整的 URL,您的链接将在您的电子邮件中正常工作。
4.2.1 使用 url_for
生成 URL
url_for
辅助方法在模板中默认情况下生成完整的 URL。
如果您没有全局配置 :host
选项,则需要将其传递给 url_for
。
<%= url_for(host: 'example.com',
controller: 'welcome',
action: 'greeting') %>
4.2.2 使用命名路由生成 URL
与其他 URL 类似,您需要在电子邮件中使用命名路由辅助方法的 *_url
变体。
您可以全局配置 :host
选项,或者确保将其传递给 URL 辅助方法
<%= user_url(@user, host: 'example.com') %>
4.3 在 Action Mailer 视图中添加图像
要使用电子邮件中的 image_tag
辅助方法,您需要指定 :asset_host
参数。这是因为邮件实例没有关于传入请求的任何上下文信息。
通常 :asset_host
在整个应用程序中都是一致的,因此您可以在 config/application.rb
中全局配置它。
config.action_mailer.asset_host = "http://example.com"
由于我们无法从请求推断协议,因此您需要在 :asset_host
配置中指定协议,例如 http://
或 https://
。
现在您可以在电子邮件中显示图像。
<%= image_tag 'image.jpg' %>
4.4 缓存邮件视图
您可以使用 cache
方法在邮件视图中执行片段缓存,类似于应用程序视图。
<% cache do %>
<%= @company.name %>
<% end %>
要使用此功能,您需要在应用程序的 config/environments/*.rb
文件中启用它。
config.action_mailer.perform_caching = true
多部分邮件也支持片段缓存。有关缓存的更多信息,请参阅 Rails 缓存指南。
4.5 Action Mailer 布局
与控制器布局一样,您也可以拥有邮件布局。邮件布局位于 app/views/layouts
中。以下是默认布局
# 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>
上面的布局位于 mailer.html.erb
文件中。默认布局名称是在 ApplicationMailer
中指定的,正如我们在前面的 生成邮件 部分中看到的 layout "mailer"
行。与控制器布局类似,您使用 yield
来在布局中渲染邮件视图。
要为给定的邮件使用不同的布局,请调用 layout
class UserMailer < ApplicationMailer
layout "awesome" # Use awesome.(html|text).erb as the layout
end
要为给定的电子邮件使用特定布局,您可以将 layout: 'layout_name'
选项传递给格式块中的渲染调用。
class UserMailer < ApplicationMailer
def welcome_email
mail(to: params[:user].email) do |format|
format.html { render layout: "my_layout" }
format.text
end
end
end
上面的代码将使用 my_layout.html.erb
文件渲染 HTML 部分,并使用通常的 user_mailer.text.erb
文件渲染文本部分。
5 发送电子邮件
5.1 发送电子邮件到多个收件人
可以通过将 :to
字段设置为电子邮件地址列表来将电子邮件发送给多个收件人。电子邮件列表可以是数组,也可以是单个字符串,用逗号分隔地址。
例如,要通知所有管理员一个新的注册
class AdminMailer < ApplicationMailer
default to: -> { Admin.pluck(:email) },
from: "[email protected]"
def new_registration(user)
@user = user
mail(subject: "New User Signup: #{@user.email}")
end
end
相同的格式可以用于添加多个抄送 (cc) 和密送 (bcc) 收件人,分别设置 :cc
和 :bcc
键(类似于 :to
字段)。
5.2 发送包含姓名的电子邮件
除了电子邮件地址之外,还可以显示接收电子邮件或发送电子邮件的人员的姓名。
要显示收件人姓名,可以在 to:
中使用 email_address_with_name
方法。
def welcome_email
@user = params[:user]
mail(
to: email_address_with_name(@user.email, @user.name),
subject: "Welcome to My Awesome Site"
)
end
from:
中的相同方法可以显示发件人姓名。
class UserMailer < ApplicationMailer
default from: email_address_with_name("[email protected]", "Example Company Notifications")
end
如果姓名为空(nil
或空字符串),则返回电子邮件地址。
5.3 发送包含主题翻译的电子邮件
如果您没有向 mail 方法传递主题,Action Mailer 将尝试在您的翻译中找到主题。有关更多信息,请参阅 国际化指南。
5.4 发送不使用模板渲染的电子邮件
在某些情况下,您可能希望跳过模板渲染步骤,而是提供电子邮件正文作为字符串。您可以使用 :body
选项实现这一点。请记住设置 :content_type
选项,例如在下面将其设置为 text/html
。Rails 默认情况下将 text/plain
作为内容类型。
class UserMailer < ApplicationMailer
def welcome_email
mail(to: params[:user].email,
body: params[:email_body],
content_type: "text/html",
subject: "Already rendered!")
end
end
5.5 发送包含动态传递选项的电子邮件
如果您希望在传递电子邮件时覆盖默认的传递 配置(例如 SMTP 凭据),可以使用邮件操作中的 delivery_method_options
来实现。
class UserMailer < ApplicationMailer
def welcome_email
@user = params[:user]
@url = user_url(@user)
delivery_options = { user_name: params[:company].smtp_user,
password: params[:company].smtp_password,
address: params[:company].smtp_host }
mail(to: @user.email,
subject: "Please see the Terms and Conditions attached",
delivery_method_options: delivery_options)
end
end
6 Action Mailer 回调
Action Mailer 允许您指定一个 before_action
、after_action
和 around_action
来配置消息,以及 before_deliver
、after_deliver
和 around_deliver
来控制邮件发送。
回调可以使用代码块或表示邮件类中方法名称的符号来指定,类似于其他回调(在控制器或模型中)。
以下是一些使用这些回调与邮件器的示例。
6.1 before_action
您可以使用 before_action
来设置实例变量,用默认值填充邮件对象,或插入默认的邮件头和附件。
class InvitationsMailer < ApplicationMailer
before_action :set_inviter_and_invitee
before_action { @account = params[:inviter].account }
default to: -> { @invitee.email_address },
from: -> { common_address(@inviter) },
reply_to: -> { @inviter.email_address_with_name }
def account_invitation
mail subject: "#{@inviter.name} invited you to their Basecamp (#{@account.name})"
end
def project_invitation
@project = params[:project]
@summarizer = ProjectInvitationSummarizer.new(@project.bucket)
mail subject: "#{@inviter.name.familiar} added you to a project in Basecamp (#{@account.name})"
end
private
def set_inviter_and_invitee
@inviter = params[:inviter]
@invitee = params[:invitee]
end
end
6.2 after_action
您可以使用 after_action
回调,其设置与 before_action
类似,但还可以访问在邮件器操作中设置的实例变量。
您还可以使用 after_action
通过更新 mail.delivery_method.settings
来覆盖发送方法设置。
class UserMailer < ApplicationMailer
before_action { @business, @user = params[:business], params[:user] }
after_action :set_delivery_options,
:prevent_delivery_to_guests,
:set_business_headers
def feedback_message
end
def campaign_message
end
private
def set_delivery_options
# You have access to the mail instance,
# @business and @user instance variables here
if @business && @business.has_smtp_settings?
mail.delivery_method.settings.merge!(@business.smtp_settings)
end
end
def prevent_delivery_to_guests
if @user && @user.guest?
mail.perform_deliveries = false
end
end
def set_business_headers
if @business
headers["X-SMTPAPI-CATEGORY"] = @business.code
end
end
end
6.3 after_deliver
您可以使用 after_deliver
来记录邮件的发送。它还允许观察者/拦截器之类的行为,但可以访问完整的邮件器上下文。
class UserMailer < ApplicationMailer
after_deliver :mark_delivered
before_deliver :sandbox_staging
after_deliver :observe_delivery
def feedback_message
@feedback = params[:feedback]
end
private
def mark_delivered
params[:feedback].touch(:delivered_at)
end
# An Interceptor alternative.
def sandbox_staging
message.to = ["[email protected]"] if Rails.env.staging?
end
# A callback has more context than the comparable Observer example.
def observe_delivery
EmailDelivery.log(message, self.class, action_name, params)
end
end
如果 body
被设置为非空值,邮件器回调将中止进一步处理。before_deliver
可以使用 throw :abort
中止。
7 Action Mailer 视图助手
Action Mailer 视图可以访问与普通视图大部分相同的助手。
还有一些特定于 Action Mailer 的辅助方法可在 ActionMailer::MailHelper
中使用。例如,这些方法允许使用 mailer
从视图中访问邮件器实例,并使用 message
访问邮件。
<%= stylesheet_link_tag mailer.name.underscore %>
<h1><%= message.subject %></h1>
8 Action Mailer 配置
本节显示一些 Action Mailer 的配置示例。
有关各种配置选项的更多详细信息,请参阅 配置 Rails 应用程序 指南。您可以在特定于环境的文件(如 production.rb)中指定配置选项。
8.1 Action Mailer 配置示例
以下是如何在 config/environments/$RAILS_ENV.rb
文件中添加使用 :sendmail
发送方法的示例。
config.action_mailer.delivery_method = :sendmail
# Defaults to:
# config.action_mailer.sendmail_settings = {
# location: '/usr/sbin/sendmail',
# arguments: %w[ -i ]
# }
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default_options = { from: "[email protected]" }
8.2 Gmail 的 Action Mailer 配置
将此添加到 config/environments/$RAILS_ENV.rb
文件中,通过 Gmail 发送邮件。
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: "smtp.gmail.com",
port: 587,
domain: "example.com",
user_name: Rails.application.credentials.dig(:smtp, :user_name),
password: Rails.application.credentials.dig(:smtp, :password),
authentication: "plain",
enable_starttls: true,
open_timeout: 5,
read_timeout: 5 }
Google 阻止 来自其认为不太安全的应用程序的登录。您可以 更改您的 Gmail 设置 以允许尝试。如果您的 Gmail 帐户启用了双重身份验证,那么您需要设置一个 应用程序密码 并使用它,而不是您的常规密码。
9 预览和测试邮件器
您可以在 测试指南 中找到有关如何测试邮件器的详细说明。
9.1 预览电子邮件
您可以通过访问特殊的 Action Mailer 预览 URL 来以视觉方式预览呈现的电子邮件模板。要为 UserMailer
设置预览,请在 test/mailers/previews/
目录中创建一个名为 UserMailerPreview
的类。要查看 UserMailer
中 welcome_email
的预览,请在 UserMailerPreview
中实现具有相同名称的方法并调用 UserMailer.welcome_email
。
class UserMailerPreview < ActionMailer::Preview
def welcome_email
UserMailer.with(user: User.first).welcome_email
end
end
现在,预览将位于 https://127.0.0.1:3000/rails/mailers/user_mailer/welcome_email 上。
如果您在 app/views/user_mailer/welcome_email.html.erb
中更改邮件器视图或邮件器本身,预览将自动更新。预览列表也位于 https://127.0.0.1:3000/rails/mailers 上。
默认情况下,这些预览类位于 test/mailers/previews
中。可以使用 preview_paths
选项配置它。例如,如果您想将 lib/mailer_previews
添加到其中,您可以在 config/application.rb
中配置它。
config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"
9.2 救援错误
邮件器方法内的救援块无法救援在渲染之外发生的错误。例如,在后台作业中记录反序列化错误,或来自第三方邮件发送服务的错误。
要救援在邮件过程的任何部分发生的错误,请使用 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
10 拦截和观察电子邮件
Action Mailer 提供了对邮件观察者和拦截器方法的钩子。这些方法允许您注册在每个发送的电子邮件的邮件发送生命周期中调用的类。
10.1 拦截电子邮件
拦截器允许您在电子邮件传递给发送代理之前对其进行修改。拦截器类必须实现 .delivering_email(message)
方法,该方法将在发送电子邮件之前被调用。
class SandboxEmailInterceptor
def self.delivering_email(message)
message.to = ["[email protected]"]
end
end
拦截器需要使用 interceptors
配置选项注册。您可以在初始化文件(如 config/initializers/mail_interceptors.rb
)中执行此操作。
Rails.application.configure do
if Rails.env.staging?
config.action_mailer.interceptors = %w[SandboxEmailInterceptor]
end
end
上面的示例使用了一个名为“staging”的自定义环境,用于生产级别的服务器,但用于测试目的。您可以阅读 创建 Rails 环境,以了解更多关于自定义 Rails 环境的信息。
10.2 观察电子邮件
观察者允许您在电子邮件发送后 访问电子邮件消息。观察者类必须实现 :delivered_email(message)
方法,该方法将在发送电子邮件后被调用。
class EmailDeliveryObserver
def self.delivered_email(message)
EmailDelivery.log(message)
end
end
与拦截器类似,您必须使用 observers
配置选项注册观察者。您可以在初始化文件(如 config/initializers/mail_observers.rb
)中执行此操作。
Rails.application.configure do
config.action_mailer.observers = %w[EmailDeliveryObserver]
end