Set the Message-ID mail header in Rails3 / ActionM

2020-02-23 07:47发布

问题:

I would like to alter the Message-ID header that is in the header portion of an email sent from a Ruby on Rails v3 application using ActionMailer.

I am using Sendmail on localhost for mail delivery.

Do I configure this in Sendmail or ActionMailer?

Where do I configure this (if it is ActionMailer): a file in config/ folder or a file in app/mailers/ folder?

回答1:

Teddy's answer is good, except that if you actually want each message to have a different ID, you need to make the default a lambda. In the first block of code in his answer, it calculates the message-ID once, at init, and uses the same one for every message.

Here's how I'm doing this in my app:

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

... with the domain taken from a custom app config variable (and using SecureRandom.uuid, which is a little more straightforward than a SHA-2 based on the timestamp IMO.)



回答2:

I usually prefer generating the message-id with a UUID. Assuming you have the uuid gem:

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

Also you should note that according to RFC 2822 the message-id should be placed inside "<" and ">"



回答3:

In Rails 4+ (or just Ruby 2.0+) the folowing syntax is working correctly:

default "Message-ID" => ->(v){"<#{Digest::SHA2.hexdigest(Time.now.to_i.to_s)}@yourdomain.com>"}

Tested this with MailCatcher.



回答4:

I figured this out. The easiest way to do is to use the default method at the top of the mailer class file.

Example:

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

However, I found this difficult to test, so I wrote a private method and used the sent_at time instead of 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

And I simply called that method before calling the mail method. This made it easy to pass a sent_at parameter from my test and verify a match in email.encoded.



回答5:

@jasoncrawford is almost right. The problem is that the mailgun_domain attribute may not be able at development environment, so it is better to access the ActionMailer configs.

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