我有一个第三方电子邮件集成库,我想用它来发送电子邮件 我的一个用户。要发送电子邮件,我使用为每个用户保存的access_token
进行API调用。
为了仍然使用动作邮件,我已经创建了一个这样的自定义投放类:
module Mail
class CustomMailDelivery
attr_reader :settings
def initialize(settings)
@settings = settings
end
def deliver!(mail)
# use 3rd party client here
end
end
end
我在初始化程序中配置它:
ActionMailer::Base.add_delivery_method :custom, Mail::CustomMailDelivery, {
app_id: ENV.fetch('3RDPARTY_APP_ID'),
app_secret: ENV.fetch('3RDPARTY_APP_SECRET'),
}
这允许我按邮件设置交付方式:
class LeadMailer < ApplicationMailer
self.delivery_method = :custom
...
end
问题是,我需要传递发送此邮件的用户,以便我可以获取他们的access_token
。
我不想依赖于使用发件人的电子邮件地址提取EmailAccount
,因为这似乎可以打破这条路(这可能是这个电子邮件地址< em>可能与发送用户不同)。
换句话说,我想明确地传递它,所以它很容易理解,我避免任何混淆。
有没有办法为自定义操作邮件传递类提供每邮件上下文?
答案 0 :(得分:1)
我最终使用自定义邮件标头传递此数据,我稍后在处理邮件时将其删除。
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
这种方式需要此行为的邮件程序从此类继承子类并被强制提供自定义数据。
在交付类中,我将这个值从标题中删除:
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
这个解决方案不是很优雅,但很有效。
答案 1 :(得分:0)
感谢这个想法,我使用register_observer
和register_interceptor
整理了一个简短的版本。
基本上是相同的想法,只是您不需要重新定义过多的交付内容。您只需挂接邮件工作流程即可。
首先,声明钩子:
ActionMailer::Base.register_observer(MailToActionEventObserver)
ActionMailer::Base.register_interceptor(MailToActionEventObserver)
然后,最简单的部分是,钩子是同一类内部的静态方法:
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相同,只需将参数作为邮件头中的标题传递即可:
def my_custom_mail
headers['MY-PERSONAL-HEADER'] = 'whatever-value'
mail(...)
end