edge
更多信息请访问 rubyonrails.org: 更多 Ruby on Rails

Action Mailbox基础知识

本指南为您提供了开始接收应用程序的电子邮件所需的所有内容。

阅读本指南后,您将了解:

1 什么是Action Mailbox?

Action Mailbox将传入的电子邮件路由到类似控制器的邮箱中,以在Rails中进行处理。它附带了用于Mailgun、Mandrill、Postmark和SendGrid的入口。您还可以通过内置的Exim、Postfix和Qmail入口直接处理传入的邮件。

传入的电子邮件使用Active Record转换为"InboundEmail"记录,并具有生命周期跟踪、通过Active Storage在云存储上存储原始电子邮件以及默认启用的负责任的数据处理。

这些传入的电子邮件使用Active Job异步路由到一个或多个专用邮箱,这些邮箱能够直接与您的域模型的其余部分进行交互。

2 设置

安装所需的"InboundEmail"迁移并确保设置好Active Storage:

$ bin/rails action_mailbox:install
$ bin/rails db:migrate

3 配置

3.1 Exim

告诉Action Mailbox接受来自SMTP中继的电子邮件:

# config/environments/production.rb
config.action_mailbox.ingress = :relay

生成一个强密码,Action Mailbox可以使用该密码对中继入口的请求进行身份验证。

使用bin/rails credentials:edit将密码添加到应用程序的加密凭据中,位置为action_mailbox.ingress_password,Action Mailbox将自动找到它:

action_mailbox:
  ingress_password: ...

或者,将密码提供给RAILS_INBOUND_EMAIL_PASSWORD环境变量。

配置Exim将传入的电子邮件导向bin/rails action_mailbox:ingress:exim,提供中继入口的URL和之前生成的INGRESS_PASSWORD。如果您的应用程序位于https://example.com,完整的命令如下所示:

$ bin/rails action_mailbox:ingress:exim URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=...

3.2 Mailgun

将您的Mailgun签名密钥(可以在Mailgun的设置->安全性和用户->API安全性下找到)提供给Action Mailbox,以便它可以对Mailgun入口的请求进行身份验证。

使用bin/rails credentials:edit将您的签名密钥添加到应用程序的加密凭据中,位置为action_mailbox.mailgun_signing_key,Action Mailbox将自动找到它:

action_mailbox:
  mailgun_signing_key: ...

或者,将您的签名密钥提供给MAILGUN_INGRESS_SIGNING_KEY环境变量。

告诉Action Mailbox接受来自Mailgun的电子邮件:

# config/environments/production.rb
config.action_mailbox.ingress = :mailgun

配置Mailgun将传入的电子邮件转发到/rails/action_mailbox/mailgun/inbound_emails/mime。如果您的应用程序位于https://example.com,您将指定完全限定的URLhttps://example.com/rails/action_mailbox/mailgun/inbound_emails/mime

3.3 Mandrill

将您的Mandrill API密钥提供给Action Mailbox,以便它可以对Mandrill入口的请求进行身份验证。

使用bin/rails credentials:edit将您的API密钥添加到应用程序的加密凭据中,位置为action_mailbox.mandrill_api_key,Action Mailbox将自动找到它:

action_mailbox:
  mandrill_api_key: ...

或者,将您的API密钥提供给MANDRILL_INGRESS_API_KEY环境变量。

告诉Action Mailbox接受来自Mandrill的电子邮件:

# config/environments/production.rb
config.action_mailbox.ingress = :mandrill

配置Mandrill将传入的电子邮件路由到/rails/action_mailbox/mandrill/inbound_emails。如果您的应用程序位于https://example.com,您将指定完全限定的URLhttps://example.com/rails/action_mailbox/mandrill/inbound_emails

3.4 Postfix

告诉Action Mailbox接受来自SMTP中继的电子邮件:

# config/environments/production.rb
config.action_mailbox.ingress = :relay

生成一个强密码,Action Mailbox可以使用该密码对中继入口的请求进行身份验证。

使用bin/rails credentials:edit将密码添加到应用程序的加密凭据中,位置为action_mailbox.ingress_password,Action Mailbox将自动找到它:

action_mailbox:
  ingress_password: ...

或者,将密码提供给RAILS_INBOUND_EMAIL_PASSWORD环境变量。

配置Postfix将传入的电子邮件导向bin/rails action_mailbox:ingress:postfix,提供之前生成的Postfix入口的URLINGRESS_PASSWORD。如果您的应用程序位于https://example.com,完整的命令如下所示:

$ bin/rails action_mailbox:ingress:postfix URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=...

3.5 Postmark

告诉Action Mailbox接受来自Postmark的电子邮件:

# config/environments/production.rb
config.action_mailbox.ingress = :postmark

生成一个强密码,Action Mailbox可以使用该密码对Postmark入口的请求进行身份验证。

使用bin/rails credentials:edit将密码添加到应用程序的加密凭据中,位置为action_mailbox.ingress_password,Action Mailbox将自动找到它:

action_mailbox:
  ingress_password: ...

或者,将密码提供给RAILS_INBOUND_EMAIL_PASSWORD环境变量。

配置Postmark入站Webhook将传入的电子邮件转发到/rails/action_mailbox/postmark/inbound_emails,用户名为actionmailbox,密码为之前生成的密码。如果您的应用程序位于https://example.com,您将使用以下完全限定的URL配置Postmark: https://actionmailbox:[email protected]/rails/action_mailbox/postmark/inbound_emails

注意:在配置Postmark入站Webhook时,请确保勾选标有“在JSON负载中包含原始电子邮件内容”的框。 Action Mailbox需要原始电子邮件内容才能正常工作。

3.6 Qmail

告诉Action Mailbox从SMTP中继接受电子邮件:

# config/environments/production.rb
config.action_mailbox.ingress = :relay

生成一个强密码,用于Action Mailbox对中继入口的请求进行身份验证。

使用bin/rails credentials:edit将密码添加到应用程序的加密凭据中, 位置为action_mailbox.ingress_password,Action Mailbox将自动找到它:

action_mailbox:
  ingress_password: ...

或者,将密码提供给RAILS_INBOUND_EMAIL_PASSWORD环境变量。

配置Qmail将入站电子邮件导入到bin/rails action_mailbox:ingress:qmail, 提供中继入口的URL和之前生成的INGRESS_PASSWORD。如果您的应用程序位于https://example.com, 完整的命令如下所示:

$ bin/rails action_mailbox:ingress:qmail URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=...

3.7 SendGrid

告诉Action Mailbox从SendGrid接受电子邮件:

# config/environments/production.rb
config.action_mailbox.ingress = :sendgrid

生成一个强密码,用于Action Mailbox对SendGrid入口的请求进行身份验证。

使用bin/rails credentials:edit将密码添加到应用程序的加密凭据中, 位置为action_mailbox.ingress_password,Action Mailbox将自动找到它:

action_mailbox:
  ingress_password: ...

或者,将密码提供给RAILS_INBOUND_EMAIL_PASSWORD环境变量。

配置SendGrid Inbound Parse 将入站电子邮件转发到 /rails/action_mailbox/sendgrid/inbound_emails,用户名为actionmailbox, 密码为之前生成的密码。如果您的应用程序位于https://example.com, 您将使用以下URL配置SendGrid:

https://actionmailbox:[email protected]/rails/action_mailbox/sendgrid/inbound_emails

注意:在配置SendGrid Inbound Parse webhook时,请确保勾选标有“发布原始的完整MIME消息。”的框。 Action Mailbox需要原始MIME消息才能正常工作。

4 示例

配置基本路由:

# app/mailboxes/application_mailbox.rb
class ApplicationMailbox < ActionMailbox::Base
  routing(/^save@/i     => :forwards)
  routing(/@replies\./i => :replies)
end

然后设置一个邮箱:

# 生成新的邮箱
$ bin/rails generate mailbox forwards
# app/mailboxes/forwards_mailbox.rb
class ForwardsMailbox < ApplicationMailbox
  # 回调指定处理的先决条件
  before_processing :require_projects

  def process
    # 在一个项目上记录转发,或者…
    if forwarder.projects.one?
      record_forward
    else
      # …涉及第二个Action Mailer,询问要转发到哪个项目。
      request_forwarding_project
    end
  end

  private
    def require_projects
      if forwarder.projects.none?
        # 使用Action Mailers将传入的电子邮件反弹回发件人 - 这会停止处理
        bounce_with Forwards::BounceMailer.no_projects(inbound_email, forwarder: forwarder)
      end
    end

    def record_forward
      forwarder.forwards.create subject: mail.subject, content: mail.content
    end

    def request_forwarding_project
      Forwards::RoutingMailer.choose_project(inbound_email, forwarder: forwarder).deliver_now
    end

    def forwarder
      @forwarder ||= User.find_by(email_address: mail.from)
    end
end

5 InboundEmail的销毁

默认情况下,成功处理的InboundEmail将在30天后销毁。 这样可以确保在用户可能取消账户或删除内容后,您不会随意保留他们的数据。 这意味着在处理电子邮件后,您应该提取所需的所有数据并将其转换为应用程序一侧的领域模型和内容。 InboundEmail只是在系统中保留额外的时间以提供调试和取证选项。

实际的销毁是通过预定运行IncinerationJob来完成的, 该作业在config.action_mailbox.incinerate_after时间后运行。 默认情况下,此值设置为30.days,但您可以在production.rb配置文件中进行更改。 (请注意,这种远期销毁调度依赖于您的作业队列能够保持那么长时间的作业。)

6 在开发中使用Action Mailbox

在开发中,能够测试传入的电子邮件而不实际发送和接收真实电子邮件非常有帮助。 为此,有一个控制器挂载在/rails/conductor/action_mailbox/inbound_emails, 它提供了系统中所有InboundEmail的索引,它们的处理状态以及创建新InboundEmail的表单。

7 测试邮箱

示例:

class ForwardsMailboxTest < ActionMailbox::TestCase
  test "直接为一个项目对应的转发者和被转发者记录客户端转发" do
    assert_difference -> { people(:david).buckets.first.recordings.count } do
      receive_inbound_email_from_mail \
        to: '[email protected]',
        from: people(:david).email_address,
        subject: "Fwd: Status update?",
        body: <<~BODY
          --- Begin forwarded message ---
          From: Frank Holland <[email protected]>

          What's the status?
        BODY
    end

    recording = people(:david).buckets.first.recordings.last
    assert_equal people(:david), recording.creator
    assert_equal "Status update?", recording.forward.subject
    assert_match "What's the status?", recording.forward.content.to_s
  end
end

请参阅ActionMailbox::TestHelper API以获取更多测试助手方法。 ```

反馈

欢迎您帮助改进本指南的质量。

如果您发现任何拼写错误或事实错误,请贡献您的意见。 要开始,请阅读我们的 文档贡献 部分。

您还可能会发现不完整的内容或过时的内容。 请为主要内容添加任何缺失的文档。请先检查 Edge 指南,以验证问题是否已经修复或尚未修复。 请参阅 Ruby on Rails 指南准则 以了解样式和规范。

如果您发现需要修复但无法自行修复的问题,请 提交问题

最后但同样重要的是,欢迎您在 官方 Ruby on Rails 论坛 上讨论有关 Ruby on Rails 文档的任何问题。