如何用 Action Mailbox 接收外部邮件并路由到自定义 Mailbox 处理
如何用 Action Mailbox 接收外部邮件并路由到自定义 Mailbox 处理【免费下载链接】railsRuby on Rails项目地址: https://gitcode.com/GitHub_Trending/rai/rails如果你需要让 Rails 应用接收外部发来的邮件例如转发邮件、回复通知Ruby on Rails 自带的 Action Mailbox 可以把入站邮件路由到类似 Controller 的 Mailbox 类中处理。它专门负责收邮件与负责发信的 Action Mailer 相对。入站邮件通过 Active Job 异步路由到一个或多个 Mailbox并被转换为InboundEmail记录基于 Active Record从而与你的领域模型交互原始邮件内容由 Active Storage 存储。完成本场景需要走通一条完整链路安装 Action Mailbox → 配置 ingress入站端点→ 在ApplicationMailbox中声明路由规则 → 生成并编写自定义 Mailbox 的process方法 → 通过 conductor 界面或测试辅助方法验证处理结果。下面每一步都给出命令、配置位置和判断依据。安装与数据库准备在应用根目录执行安装命令$ bin/rails action_mailbox:install这一步会创建application_mailbox.rb文件并复制迁移文件。随后运行迁移$ bin/rails db:migrate这会执行 Action Mailbox 与 Active Storage 的迁移。其中action_mailbox_inbound_emails表用于存储入站消息及其处理状态是后面验证邮件是否被处理的核心对象。安装完成后可以先启动 Rails 服务器访问http://localhost:3000/rails/conductor/action_mailbox/inbound_emails查看 conductor 页面开发环境下的验证入口详见结果验证一节。配置 Ingress外部邮件从哪里进来Ingress 决定外部邮件如何进入应用。Action Mailbox 内置了针对 Mailgun、Mandrill、Postmark、SendGrid 的 ingress以及可直接对接 Exim、Postfix、Qmail 的管道方式relay 模式。选择哪一种取决于你使用的外部邮件服务。以Mailgun为例文档给出的最短主路径之一从 Mailgun 后台获取 Signing keySettings - Security Users - API security让 Action Mailbox 能够鉴权发往 Mailgun ingress 的请求。用bin/rails credentials:edit把 Signing key 写入加密凭证的action_mailbox.mailgun_signing_key下Action Mailbox 会自动读取该位置# config/credentials.yml.enc 中新增 action_mailbox: mailgun_signing_key: ...替代方案把 Signing key 放到环境变量MAILGUN_INGRESS_SIGNING_KEY中。 3. 在环境配置中声明接受 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。注意端点必须以mime结尾Mailgun 只有这样才会传递原始邮件内容见 config/routes.rb 中对该 ingress 路由的注释。可选分支SMTP 管道relay方式。如果你使用 Exim、Postfix 或 Qmail 直接把邮件管道给应用统一配置为# config/environments/production.rb config.action_mailbox.ingress :relay同样用bin/rails credentials:edit生成一个强密码写入action_mailbox.ingress_password或改用环境变量RAILS_INBOUND_EMAIL_PASSWORD。以 Exim 为例把入站邮件管道到如下命令URL是 relay ingress 地址INGRESS_PASSWORD是刚才生成的密码$ bin/rails action_mailbox:ingress:exim URLhttps://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD...Postfix、Qmail 分别对应action_mailbox:ingress:postfix和action_mailbox:ingress:qmail参数相同。这些任务的实现见 ingress.rake它们从STDIN读取原始邮件并 POST 到URLURL或INGRESS_PASSWORD缺失时会直接报错退出exim 任务输出URL and INGRESS_PASSWORD are required退出码 64退出码会区分成功、临时失败与不可用方便 SMTP 服务器重试。Postmark 与 SendGrid 的 ingress 使用基本相同的 relay 凭证模式action_mailbox.ingress_password区别在外部配置两者都需要在 webhook URL 中使用用户名actionmailbox 你生成的密码且必须在外部服务勾选传递原始邮件内容的选项Postmark 的 Include raw email content in JSON payloadSendGrid 的 Post the raw, full MIME message否则 Action Mailbox 无法工作。配置路由邮件进入后分发给哪个 Mailbox邮件经 ingress 进入后还需要决定由哪个 Mailbox 处理。与 Rails router 把 URL 分发给 Controller 类似Action Mailbox 在ApplicationMailbox中用routing声明路由规则# app/mailboxes/application_mailbox.rb class ApplicationMailbox ActionMailbox::Base routing(/^save/i :forwards) routing(/replies\./i :replies) end规则左侧可以写正则、字符串或可调用对象右侧是目标 mailbox 名称。匹配逻辑正则会匹配邮件to、cc或bcc字段中的任意一个收件人例如/^save/i匹配所有发给save...地址的邮件字符串要求某个收件人精确匹配如helpexample.com :help传 proc/lambda 等可调用对象时会收到inbound_email记录返回 true 即匹配如-(inbound_email) { inbound_email.mail.to.size 2 } :multiple_recipientsrouting :all :backstop可作为兜底接住所有未被前面规则匹配的邮件。以上写法的依据是 base.rb 中ActionMailbox::Base的类文档。路由的实际执行由 router.rb 完成按声明顺序逐条match?命中即mailbox.receive(inbound_email)没有任何规则命中时邮件会被标记为bounced!并抛出RoutingError——所以如果你的业务要求所有邮件都有归宿务必加:all兜底规则。生成并编写自定义 Mailbox针对上面路由到的forwards生成 mailbox 类$ bin/rails generate mailbox forwards生成器会在app/mailboxes/forwards_mailbox.rb创建ForwardsMailbox类含空的process方法同时如果app/mailboxes/application_mailbox.rb尚不存在会一并创建ApplicationMailbox的模板内容见 application_mailbox.rb.tt。生成器说明见 mailbox 生成器 USAGE。process方法在回调执行完毕后由框架调用。处理时可以通过inbound_email.mail拿到解析后的Mail对象用inbound_email.source取原始邮件内容。文档给出的字段访问示例文档示例值来自官方测试邮件irb mail.to [saveexample.com] irb mail.from [someonehey.com] irb mail.subject Hello Action Mailbox irb mail.body.decoded This is the body of the email message. # mail.decoded, a shorthand for mail.body.decoded, also works irb mail.decoded This is the body of the email message.一个完整的 mailbox 示例用before_processing回调检查前置条件不满足时用bounce_with把邮件退回发送者这会中止处理满足则基于邮件数据创建 Active Record 记录# app/mailboxes/forwards_mailbox.rb class ForwardsMailbox ApplicationMailbox # Callbacks specify prerequisites to processing before_processing :require_projects def process # Record the forward on the one project, or… if forwarder.projects.one? record_forward else # …involve a second Action Mailer to ask which project to forward into. request_forwarding_project end end private def require_projects if forwarder.projects.none? # Use Action Mailers to bounce incoming emails back to sender – this halts processing bounce_with Forwards::BounceMailer.no_projects(inbound_email, forwarder: forwarder) end end def record_forward forwarder.forwards.create subject: mail.subject, content: mail.decoded 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可用的回调有before_processing、after_processing、around_processing。此外bounce_with(message)将入站邮件状态置为bounced并异步投递退回邮件bounce_now_with立即投递若想静默拒绝不发退回邮件在回调中调用bounced!即可中止后续处理异常可用rescue_from在类级别捕获rescue_from(ApplicationSpecificVerificationError) { bounced! }未处理的异常会把状态标记为failed。结果验证与本地开发 conductor用 conductor 界面观察真实状态开发环境中有一个 conductor 控制器挂载在/rails/conductor/action_mailbox/inbound_emails提供所有InboundEmail的索引、处理状态以及手工创建新 InboundEmail 的表单——不需要真实收发邮件就能测试整条链路。其路由定义见 config/routes.rb包括reroute重新路由、incinerate手动销毁等操作。处理过程中Action Mailbox 会更新action_mailbox_inbound_emails表中的状态字段取值为pending已被 ingress 控制器接收等待路由processing正在处理某个 mailbox 的process方法运行中delivered已被该 mailbox 成功处理failedprocess方法执行中抛出异常bounced被 mailbox 拒绝处理并退回发送者。因此验证方式是发送或经 conductor 表单创建一封匹配你路由规则的邮件后在 conductor 页面或数据库中确认该记录最终落到delivered若为failed说明process中有未捕获异常需回看 mailbox 代码。用测试辅助方法做回归验证ActionMailbox::TestHelper提供receive_inbound_email_from_mail等方法可构造入站邮件并立即路由处理实现见 test_helper.rb。官方示例引自 guides/source/action_mailbox_basics.mdclass ForwardsMailboxTest ActionMailbox::TestCase test directly recording a client forward for a forwarder and forwardee corresponding to one project do assert_difference - { people(:david).buckets.first.recordings.count } do receive_inbound_email_from_mail \ to: saveexample.com, from: people(:david).email_address, subject: Fwd: Status update?, body: ~BODY --- Begin forwarded message --- From: Frank Holland frankmicrosoft.com Whats the status? BODY end end end这里to: saveexample.com会命中routing(/^save/i :forwards)从而驱动ForwardsMailbox执行属于文档中的测试示例代码其中的people、buckets等 fixture 属于示例应用的领域模型需替换为你自己的模型。限制与边界状态为delivered、failed、bounced的邮件视为已处理会被排定销毁IncinerationJob按config.action_mailbox.incinerate_after默认30.days延迟执行可在production.rb中修改该值。处理邮件时应立刻把需要的数据提取并持久化到领域模型InboundEmail保留一段时间仅供调试与取证之后删除。长时间延迟销毁依赖你的作业队列能挂起这么久配置更长的incinerate_after前需确认队列支持。路由未命中任何规则不是静默忽略而是bouncedRoutingErroringress 未配置或凭证缺失时外部请求无法通过鉴权这些属于不同环节的问题应分别在 conductor 状态、日志与外部服务配置中定位。【免费下载链接】railsRuby on Rails项目地址: https://gitcode.com/GitHub_Trending/rai/rails创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考