Ruby:抄送地址的电子邮件丢失

Ruby: Emails go missing for Cc addresses

问题总结

当我尝试将地址包含到 CC 字段时,Ruby mailfactory gem(或 Net::SMTP)出现问题。我不确定我可能用错了两者中的哪一个。

两个 test/production 系统的 mailfactory 版本相同,但 Ruby 安装的版本不同。我正在使用 mailfactory (1.4.0)。测试系统有ruby 2.1.2p95 (2014-05-08) [x86_64-linux-gnu],生产系统有ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-linux].

当前代码

这是我的 email-sending 函数中的代码:

mail = MailFactory.new

to_addr   = 'to@domain.com'
cc_addr   = ['cc1@domain.com', 'cc2@domain.com']
#
# ...ommitted for brevity...
#
mail.to       = to_addr
mail.cc       = cc_addr.join ';'
mail.from     = 'from@domain.com'
mail.subject  = "Subject here"
mail.text     = "Some text here"
mail.html     = "Some HTML text here"

Net::SMTP.start('smtp-host@domain.com', 25) do |smtp|
  smtp.send_message(mail.to_s, mail.from.to_s, to_addr)
end

上面的代码有效,但只是部分有效。当我 运行 我的 测试 (并且只有 有时 )时,CC 列表中的那些人似乎会收到电子邮件,但是当代码 运行s in production,CC 列表中似乎没有人收到副本。 (我碰巧在 CC 列表中,但我从来没有得到过任何一个。)

我尝试了几种不同的方法,包括将 to_addrcc_addr 连接成一个字符串,如下所示:

cc_addr << to_addr
Net::SMTP.start('smtp-host@domain.com', 25) do |smtp|
  smtp.send_message(mail.to_s, mail.from.to_s, cc_addr.join(';'))
end

这也没有用。

我也试过使用mailfactoryadd_header方法:

mail.add_header('To', to_addr)
mail.add_header('Cc', cc_addr.join(';'))
mail.add_header('From', "from@domain.com")
# etc...

这也没有用。 CC 列表中的地址不会收到消息(即使在曾经有效的测试环境中也不会)。事实上,即使 CC 包含单个字符串,它仍然不起作用。

其他观察结果

这里还有一些我直接观察到的东西:

  1. 当我 puts mail.to_s 到终端时,邮件 headers 似乎没问题(即我看到了地址,包括抄送 - 请参阅下面的示例);

  2. 当用户回复其中一封收到的电子邮件时,所有地址都清楚地列在抄送字段中,即使似乎没有人收到(至少我知道我没有收到) );

  3. 其他 non-Ruby 程序使用相同的 SMTP 服务器 (IT-managed) 发送电子邮件,包括抄送,没有问题;

  4. 程序 运行 运行正常(即没有出现警告或错误消息);

  5. 电子邮件地址有效,即使我曾经收到一个这样的地址的邮件发送通知失败(没有再看到,似乎是 IT 方面的 one-time 问题)

  6. 尝试将多个地址 join 放入 To: 字段中是行不通的。 (源代码似乎将 to 字段限制为 单个 地址。)

我已经检查过其他 references/examples,但它们非常简单,只关注单个 To:From: 等。因为这似乎对我有用,它们没有用。

Header 示例 1

这是真实的电子邮件 headers,由 puts mail.to_s 生成,地址和域出于显而易见的原因进行了编辑。

下面的headers是使用

制作的
mail.add_header('To:', 'to@domain.com')
mail.add_header('From:', 'from@domain.com')
mail.add_header('Cc:', 'cc1@domain.com')

...等等。输出是:

To: to@domain.com
From: from@domain.com
Cc: cc1@domain.com
Cc: cc2@domain.com
Reply-to: from@domain.com
Subject: The subject
Message-ID: <1455811642.9742095.1000.11119260@domain.com>
Date: Thu, 18 Feb 2016 08:07:22 -0800
MIME-Version: 1.0
Content-Type: multipart/alternative;boundary="----=_NextPart_APX_H3L1_qoWN58XIkVGr5SL_"

Header 示例 2

下面的headers是使用

制作的
mail.to = 'to@domain.com'
mail.cc = cc_addr.join ';'

...等等。他们制作了:

to: to@domain.com
cc: cc1@domain.com;cc2@domain.com
from: from@domain.com
subject: =?utf-8?Q?The_subject?=
Message-ID: <1455812736.522942.1000.7983900@domain.com>
Date: Thu, 18 Feb 2016 08:25:36 -0800
MIME-Version: 1.0
Content-Type: multipart/alternative;boundary="----=_NextPart_hTUHy..uLF3qVgnLqYEaQKd21"

headers中的不同大小写似乎没有什么区别。在这两种情况下,只有 To: 字段中列出的地址才能收到邮件。 Cc: 中的那些人没有。

问题

  1. 关于我可能在这里遗漏的任何想法?

  2. 我应该使用 mailfactory 吗? (最近注意到一些回购协议,他们的最后一次提交是在 8 年前……)

  3. 如果这是 deprecated/obsoleted,它的替代品是什么?我在哪里可以找到它 + docs/examples? (我没有找到对 mailfactory...有意义的文档)

  4. 我是在使用 Net::SMTP 不正确还是只是遗漏了什么?

我一直在浏览其他几个库,我看到 mailPony 在不同的 SO post 中被建议,但我不确定我是否只是 运行 遇到同样的问题...

感谢帮助。

其他参考资料

我已经完成了其他 SO 问题,包括但不限于以下问题。我尝试了他们的一些建议,但它们似乎对我不起作用。

  1. Ruby Net::SMTP - Send email with bcc: recipients

  2. Email subject not correctly assigned with Ruby net/smtp

您最好使用 "actionmailer" 或 "mail" 宝石。两者都有很好的文档。

https://github.com/rails/rails/tree/master/actionmailer

https://github.com/mikel/mail

我最终放弃使用 mailfactory 来尝试 mail,但我遇到了文档中未涵盖的问题。以下基于文档的示例:

Mail.defaults do
  delivery_method :smtp, address: 'smtp.domain.com', port: 25
end

Net::SMTPServerBusy 异常而失败:

/usr/lib/ruby/2.1.0/net/smtp.rb:957:in `check_response': 450 4.7.1 <localhost.localdomain>: Helo command rejected: Service temporarily unavailable (Net::SMTPServerBusy)

出于某种原因,它坚持使用 localhost 而不是 address 键指定的指定服务器。对我来说,这看起来像是 mail (2.6.3) 中的错误...虽然我可能遗漏了一些东西。

相反,我不得不添加 :domain => 'domain.com' 对来解决这个问题,如下所示:

options = {
  :address => 'smtp.domain.com',
  :port    => 25,
  :domain  => 'domain.com'  # <<-- required
}

Mail.defaults do
  delivery_method :smtp, options
end

This this SO post 对解决这个问题很有帮助。


EDIT-1: 虽然这在测试环境中确实有效,但生产环境仍然存在问题。完全解决后,我会更新此 post。

EDIT-2: 结果是 SMTP 服务器导致 Net::SMTPFatalError 异常,错误消息 Relay access denied。我不确定为什么会这样,但这似乎是 IT 部门如何配置服务器的副作用。

相反,为了解决 Net::SMTPFatalError 我必须使用不同的内部 SMTP 服务器,该服务器已配置为允许将电子邮件中继到内部地址。

在昨天 运行 程序投入生产后,之前丢失的电子邮件开始按预期出现。