在Rails3 / ActionMailer中设置邮件头Message-ID

17

我想改变在使用ActionMailer发送电子邮件时,位于邮件头部的Message-ID标头。

我在本地主机上使用Sendmail进行邮件传送。

我该在Sendmail还是ActionMailer中进行配置?

如果是在ActionMailer中配置,我应该在config/文件夹中的文件还是在app/mailers/文件夹中的文件中进行配置?

5个回答

22

Teddy的回答很好,但是如果你真的想让每个消息都有不同的ID,就需要将默认值设置为lambda函数。在他回答的第一段代码中,它只在初始化时计算了一次message-ID,并在每个消息中使用了相同的ID。

这是我在我的应用程序中所做的方式:

default "Message-ID" => lambda {"<#{SecureRandom.uuid}@#{Rails.application.config.mailgun_domain}>"}

使用从自定义应用程序配置变量中获取的域名(并使用SecureRandom.uuid,这比基于时间戳的SHA-2更直观,我个人认为。)


1
顺便提一下 - message-id 必须放在 "< >" 之间 - 否则,它不符合邮件标准。因此,代码将是:默认 "Message-ID" => lambda {"<#{SecureRandom.uuid}@#{Rails.application.config.mailgun_domain}>"} - andrewleung
2
虽然这基本上是正确的答案,但我认为应该进行编辑以包括<>,正如@andrewleung所提到的那样。否则,它将被忽略。默认 "Message-ID" => lambda {"<#{SecureRandom.uuid}@#{Rails.application.config.mailgun_domain}>"} - lsaffie
在 Ruby 1.9.3-p484 中,我不得不在 lambda 函数中添加 |v| 以避免异常:wrong number of arguments (1 for 0) - sorens
@sorens 或者使用 proc { ... } 而不是 lambda { |v| ... } ?? 不确定,但有一个建议是在 Ruby 1.9 中开始关注精确的参数计数,至少当前的 ActionMailer 正在传递一个对象。 - Justin Maxwell
由于Mail::Message具有message_id属性(文档),您可以编写default message_id: -> { "my@id.com" }。尖括号会自动添加。 - undefined
显示剩余2条评论

8

我通常更喜欢使用UUID生成消息ID。假设您已经安装了uuid gem:

headers['Message-ID'] = "<#{ UUID.generate }@example.com>"

此外,根据RFC 2822规定,邮件的message-id应该被放在"<"和">"之间。


我在其他代码中经常使用uuid gem。这是一个很好的建议。与当前时间戳的SHA256校验和相比,使用UUID更好。 - Teddy
似乎自从Ruby 1.9.3版本以后,您不需要使用gem来完成这个操作:require 'securerandom',然后跟上SecureRandom.uuid - chriscz

6
在Rails 4+(或仅限于Ruby 2.0+)中,以下语法可以正常工作:
default "Message-ID" => ->(v){"<#{Digest::SHA2.hexdigest(Time.now.to_i.to_s)}@yourdomain.com>"}

我用MailCatcher测试过了。


4

我明白了。最简单的方法是在邮件类文件的顶部使用default方法。

例如:

require 'digest/sha2'
class UserMailer < ActionMailer::Base
  default "Message-ID"=>"#{Digest::SHA2.hexdigest(Time.now.to_i.to_s)}@yourdomain.com"

  # ... the rest of your mailer class
end

然而,我发现这很难测试,所以我编写了一个私有方法,并使用sent_at时间代替Time.now
def message_id_in_header(sent_at=Time.now)
  headers["Message-ID"] = "#{Digest::SHA2.hexdigest(sent_at.to_i.to_s)}@yourdomain.com"
end

在调用mail方法之前,我只是简单地调用了那个方法。这使得我可以轻松地从我的测试中传递一个sent_at参数,并验证在email.encoded中是否匹配。


3
如果你想让每条消息都有不同的ID,那么需要将默认值设置为lambda函数。在上面的第一个代码块中,它只在初始化时计算一次消息ID,并在每条消息中使用相同的ID。啊,我正在试图在这里贴一些代码,但StackOverflow不允许我格式化它。我会添加另一个答案。 - jasoncrawford
1
这种方法的一个问题是,如果您每秒发送多封电子邮件,所有电子邮件都将具有相同的消息 ID。 - Sairam

3

@jasoncrawford几乎是正确的。问题在于mailgun_domain属性在开发环境可能无法使用,因此最好访问ActionMailer配置。

default "Message-ID" => lambda {"<#{SecureRandom.uuid}@#{ActionMailer::Base.smtp_settings[:domain]}>"}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接