Skip to content

Ruby on Rails - 发送电子邮件

Action Mailer 是 Rails 中负责发送和接收邮件的组件。它允许您创建继承自 ApplicationMailer(后者又继承自 ActionMailer::Base)的 Mailer 类来处理邮件投递。

让我们创建一个简单的应用程序 mail_sender_app,来演示如何发送邮件。

$ rails new mail_sender_app
$ cd mail_sender_app

Action Mailer 的配置通常在特定环境的文件中完成(例如,config/environments/development.rb, config/environments/production.rb)。

  1. 设置投递方式: 在 config/environments/development.rb 中,指定邮件如何投递。对于开发环境,letter_opener_web 是一个很棒的 gem,它可以在浏览器中打开发送的邮件。对于生产环境,您会使用 :smtp 或 SendGrid、Postmark 等服务。
# Gemfile
gem 'letter_opener_web', group: :development
# 然后运行: $ bundle install
config/environments/development.rb
Rails.application.configure do
# ... 其他配置 ...
config.action_mailer.delivery_method = :letter_opener_web # 用于开发环境
config.action_mailer.perform_deliveries = true # 确保邮件实际发送
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } # 对邮件中的链接很重要
end
  1. SMTP 设置 (用于生产环境或在开发环境中使用 SMTP): 如果使用 SMTP,请配置地址、端口、域名、用户名和密码等设置。切勿硬编码凭据;请使用 Rails credentials 或环境变量。
# config/environments/production.rb (Gmail SMTP 示例 - 谨慎使用,推荐使用应用专用密码)
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'smtp.gmail.com',
port: 587,
domain: 'yourdomain.com', # 或您的应用域名
user_name: ENV['GMAIL_USERNAME'],
password: ENV['GMAIL_APP_PASSWORD'],
authentication: 'plain',
enable_starttls_auto: true
}

使用 Rails 生成器创建 Mailer。让我们创建一个 UserMailer,包含一个 welcome_email 动作:

$ bin/rails generate mailer UserMailer welcome_email

这会创建 app/mailers/user_mailer.rb 和位于 app/views/user_mailer/ 的视图模板文件。

编辑 app/mailers/user_mailer.rb:

class UserMailer < ApplicationMailer
default from: 'notifications@example.com' # 默认发件人地址
def welcome_email(user)
@user = user
@url = 'http://example.com/login' # 邮件中的示例 URL
mail(to: @user.email, subject: 'Welcome to Our Awesome Site!')
# Rails 会在 app/views/user_mailer/ 目录下查找 welcome_email.html.erb 和 .text.erb 模板
end
end
  • default from: 设置此 Mailer 发送的所有邮件的默认发件人。
  • 在 welcome_email(user) 中,@user 使 user 对象在视图模板中可用。
  • mail(to: ..., subject: ...) 发送邮件。如果同时存在 HTML 和文本模板,Rails 会自动创建多部分邮件。
  1. HTML 模板 (app/views/user_mailer/welcome_email.html.erb):
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />
</head>
<body>
<h1>Welcome to example.com, <%= @user.name %>!</h1>
<p>
您已成功注册 example.com,您的用户名是:<%= @user.login %>。<br>
</p>
<p>
要登录网站,请点击此链接:<%= link_to '登录', @url %>。
</p>
<p>感谢您的加入,祝您有愉快的一天!</p>
</body>
</html>
  1. 文本模板 (app/views/user_mailer/welcome_email.text.erb):
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!

通常在特定事件发生后(例如,用户注册),您会从控制器或后台作业中发送邮件。

首先,让我们建立一个简单的 User 模型和控制器:

$ bin/rails generate scaffold User name:string email:string login:string
$ bin/rails db:migrate

修改 app/controllers/users_controller.rb 中的 create 动作,以发送欢迎邮件:

class UsersController < ApplicationController
# ... 其他动作 (index, new, show, edit, update, destroy) ...
# POST /users
def create
@user = User.new(user_params)
if @user.save
# 告诉 UserMailer 在保存后发送欢迎邮件
# .deliver_later 使用 Active Job 异步发送邮件 (推荐)
UserMailer.welcome_email(@user).deliver_later
redirect_to @user, notice: '用户创建成功。请检查您的邮箱!'
else
render :new, status: :unprocessable_entity
end
end
private
def user_params
params.require(:user).permit(:name, :email, :login)
end
end
  1. 启动您的 Rails 服务器:$ bin/rails s
  2. 如果使用 letter_opener_web,在浏览器中访问 http://localhost:3000/letter_opener。
  3. 访问 http://localhost:3000/users/new 创建一个新用户。
  4. 填写表单并提交。如果成功,邮件应该被“发送”。
  5. 检查 letter_opener_web(或您配置的邮件投递系统)以查看邮件。

日志文件(log/development.log)也会显示邮件发送的详细信息:

Rendering user_mailer/welcome_email.html.erb within layouts/mailer
Rendered user_mailer/welcome_email.html.erb within layouts/mailer (Duration: X.Xms)
Rendering user_mailer/welcome_email.text.erb within layouts/mailer
Rendered user_mailer/welcome_email.text.erb within layouts/mailer (Duration: X.Xms)
UserMailer#welcome_email: processed outbound mail in XXX.Xms
Sent mail to user@example.com (XXX.Xms)
[ActiveJob] Enqueued ActionMailer::MailDeliveryJob (Job ID: xxxxx) to SendGrid(mail)
...

更多信息:关于附件、内嵌图片和 Mailer 测试等高级主题,请参阅官方的 Action Mailer 基础指南。