如何保存Noticed gem发送的邮件?自定义DeliveryJob失效问题解决
解决Noticed发送邮件时无法记录邮件数据的问题
问题背景
自定义了Jobs::EmailDeliveryJob并绑定到ApplicationMailer,手动调用邮件方法时能正常将邮件数据存入SentEmails表,但通过Noticed的deliver_by :email发送邮件时,会跳过这个自定义Job,无法获取邮件主题和正文进行存储。
可行解决思路
思路1:让Noticed调用自定义DeliveryJob
Noticed默认的邮件投递逻辑会直接调用deliver_now/deliver_later,不会关联我们自定义的Job。可以重写Noticed的Email投递方法,强制使用自定义Job:
# config/initializers/noticed.rb Noticed::DeliveryMethods::Email.class_eval do def deliver mailer_class = Object.const_get(mailer) mail_instance = mailer_class.send(method, *args, **kwargs) # 调用自定义DeliveryJob,而非默认的投递逻辑 Jobs::EmailDeliveryJob.perform_later( mailer_class.name, method, mail_instance.delivery_method, args: args, kwargs: kwargs, params: { user: recipient } # 根据你的需求传递参数,这里假设recipient是用户对象 ) end end
这样Noticed发送的邮件会走自定义Job,原有的SentEmail存储逻辑就能正常执行。
思路2:在Noticed邮件生成后直接记录数据
不需要依赖DeliveryJob,利用Noticed的钩子在邮件实例生成后直接存储数据:
单通知类实现
在具体的Noticed通知类中添加before_deliver钩子:
class SomeNotification < Noticed::Base deliver_by :email, mailer: 'SomeMailer', method: :mail_type, delay: 1.second do |config| config.before_deliver do |notification, mail| SentEmail.create!( user: notification.user, email_type: "#{mail.class.name.deconstantize}.#{mail.method_name}", subject: mail.subject, sent_at: Time.zone.now, content: mail.body.to_s ) end end end
全局通用实现
创建一个基础通知类,所有通知继承它,统一处理邮件记录:
# app/notices/application_notice.rb class ApplicationNotice < Noticed::Base before_deliver :persist_sent_email private def persist_sent_email return unless delivery_method == :email # 生成邮件实例 mailer_class = Object.const_get(mailer) mail = mailer_class.send(method, *args, **kwargs) SentEmail.create!( user: self.user, # 确保通知类中存在user属性,按需调整 email_type: "#{mailer}.#{method}", subject: mail.subject, sent_at: Time.zone.now, content: mail.body.to_s ) end end
后续所有通知类继承ApplicationNotice即可自动记录邮件数据。
为什么扩展Noticed::Base#deliver无效?
Noticed::Base#deliver是调度投递方法的入口,此时邮件尚未生成,无法获取主题、正文等有效数据,必须在邮件实例创建完成后(如before_deliver钩子、DeliveryJob执行阶段)进行处理。
内容的提问来源于stack exchange,提问作者fpiskur
相关产品推荐
相关产品推荐

