You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails使用deliver_later报错Unsupported Argument Type: Address

解决Rails中deliver_later触发的ActiveJob::SerializationError问题

问题根源

deliver_later依赖ActiveJob将任务序列化后存入队列,而你提前构建的Mail对象中包含Mail::Address实例——这类对象不在ActiveJob默认支持的序列化类型范围内,从而抛出Unsupported argument type: Address错误。deliver_now是同步执行,无需序列化,因此不会触发这个问题。


方案1:重构代码,直接调用邮件类方法(推荐)

放弃提前构建mail_collection,改为直接调用邮件发送类的方法并链式调用deliver_later。ActiveJob会序列化方法的参数(通常是字符串、整数等可序列化类型),而非完整的Mail对象,从根源避免序列化问题。

原代码:

mail_collection.each &:deliver_now

重构示例(假设邮件类为UserMailer,发送方法为alert_email):

# 用存储原始参数的集合替代mail_collection
email_tasks.each do |task|
  UserMailer.alert_email(
    task[:recipient_email],
    task[:subject],
    task[:content]
  ).deliver_later(wait_until: specified_time)
end

方案2:提取可序列化参数,通过自定义Job发送

若必须保留mail_collection的构建逻辑,可将Mail对象的核心属性转换为可序列化格式,通过自定义ActiveJob重新构建并发送邮件:

  1. 创建自定义Job:
class SendQueuedEmailJob < ApplicationJob
  queue_as :default

  def perform(email_attrs)
    Mail.new(email_attrs).deliver_now
  end
end
  1. 修改原代码,转换Mail对象为哈希:
mail_collection.each do |mail|
  email_attrs = {
    from: mail.from.map(&:to_s), # 将Address实例转为字符串
    to: mail.to.map(&:to_s),
    cc: mail.cc&.map(&:to_s),
    subject: mail.subject,
    body: mail.body.to_s
    # 按需添加其他可序列化的邮件属性
  }
  SendQueuedEmailJob.perform_later(email_attrs, wait_until: specified_time)
end

方案3:为Mail::Address添加自定义序列化器(不推荐)

通过实现ActiveJob自定义序列化器,让Mail::Address实例支持序列化。此方法需维护序列化逻辑,若Mail::Address内部结构变更可能失效:

  1. 创建序列化器文件:
# app/serializers/address_serializer.rb
class AddressSerializer < ActiveJob::Serializers::ObjectSerializer
  def serialize?(object)
    object.is_a?(Mail::Address)
  end

  def serialize(address)
    super(
      address: address.address,
      display_name: address.display_name,
      local: address.local,
      domain: address.domain
    )
  end

  def deserialize(hash)
    Mail::Address.new.tap do |addr|
      addr.address = hash[:address]
      addr.display_name = hash[:display_name]
      addr.local = hash[:local]
      addr.domain = hash[:domain]
    end
  end
end
  1. 注册序列化器:
# config/initializers/active_job_serializers.rb
Rails.application.config.active_job.custom_serializers << AddressSerializer

内容的提问来源于stack exchange,提问作者Edward Caulfield

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 17:30:12