首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将额外信息传递给自定义操作邮件传递类。

将额外信息传递给自定义操作邮件传递类。
EN

Stack Overflow用户
提问于 2017-11-14 01:43:26
回答 2查看 945关注 0票数 2

我有一个第三方电子邮件集成库,我想用来发送电子邮件作为我的用户之一。为了发送电子邮件,我使用为每个用户保存的access_token进行API调用。

为了仍然使用action mailer,我创建了一个自定义传递类,如下所示:

代码语言:javascript
运行
复制
module Mail
  class CustomMailDelivery
    attr_reader :settings

    def initialize(settings)
      @settings = settings
    end

    def deliver!(mail)
      # use 3rd party client here
    end
  end
end

我在初始化器中配置它:

代码语言:javascript
运行
复制
ActionMailer::Base.add_delivery_method :custom, Mail::CustomMailDelivery, {
  app_id: ENV.fetch('3RDPARTY_APP_ID'),
  app_secret: ENV.fetch('3RDPARTY_APP_SECRET'),
}

这使我可以在每个邮件的基础上设置发送方法:

代码语言:javascript
运行
复制
class LeadMailer < ApplicationMailer
  self.delivery_method = :custom

  ...
end

问题是,我需要传递发送这条消息的用户,这样我就可以得到他们的access_token

我不想依赖于使用发件人的电子邮件地址获取EmailAccount,因为这似乎会破坏道路(可能这个电子邮件地址可能与发送者的用户不一样)。换句话说,我想显式地传递它,所以它很容易理解,而且我避免了任何混淆。

是否有向自定义操作邮件传递类提供每封邮件上下文的方法?

EN

回答 2

Stack Overflow用户

发布于 2017-11-22 14:22:12

最后,我使用自定义消息头传递此数据,稍后在处理消息时删除该消息。

代码语言:javascript
运行
复制
class CustomMailer < ApplicationMailer
  self.delivery_method = :custom

  attr_reader :sending_account

  def mail(params)
    raise 'You must call set_sending_account before calling mail.' unless sending_email_account
    super(params.merge({
        Mail::CustomMailDelivery::ACCOUNT_ID_HEADER => sending_account.id
      }))
  end

  def set_sending_account(account)
    @sending_account = account
  end
end

这样,需要此类行为子类并被迫提供自定义数据的邮件程序。

在传递类中,我将此值从标题中删除:

代码语言:javascript
运行
复制
module Mail
  class CustomMailDelivery
    attr_reader :settings

    # we'll hijack email headers in order to pass over some required data from the mailer to this class
    ACCOUNT_ID_HEADER = '__account_id'

    def initialize(settings)
      @settings = settings
    end

    def deliver!(mail)
      account = account_for(mail)
      client = third_party_api_client(account.access_token)
      client.send_message(...)
    end

    private

    def third_party_api_client(access_token)
      # ...
    end

    def account_for(mail)
      header_field = mail[ACCOUNT_ID_HEADER]
      missing_account_id_header! unless header_field
      email_account = Account.find(header_field.value)

      # remove the header field so it doesn't show up in the actual email
      mail[ACCOUNT_ID_HEADER] = nil

      account
    end

    def missing_account_id_header!
      raise "Missing required header: #{ACCOUNT_ID_HEADER}"
    end
  end
end

这个解决方案不是很优雅,但很有效。

票数 2
EN

Stack Overflow用户

发布于 2019-03-07 22:02:20

谢谢您的想法,我使用register_observerregister_interceptor编写了一个更短的版本。

这基本上是一样的想法,但你不需要重新定义太多的送货的东西。你只需加入邮件工作流程。

首先,声明钩子:

代码语言:javascript
运行
复制
ActionMailer::Base.register_observer(MailToActionEventObserver)
ActionMailer::Base.register_interceptor(MailToActionEventObserver)

然后,简单的部分是钩子是同一个类中的静态方法:

代码语言:javascript
运行
复制
class MailToActionEventObserver
  def self.delivered_email(mail)
    # Here you can use @passed_argument because it is called just after
    # self.delivering_email
  end

  def self.delivering_email(mail)
    @passed_argument = mail['MY-PERSONAL-HEADER'].to_s
    # Now remove the temporary header:
    mail['MY-PERSONAL-HEADER'] = nil
  end
end

现在,与您的答案@Ben一样,只需将参数作为邮件中的标题传递:

代码语言:javascript
运行
复制
def my_custom_mail
  headers['MY-PERSONAL-HEADER'] = 'whatever-value'
  mail(...)
end
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47276356

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档