« OSXクラッシュしまくり | Main | メモリ不具合疑惑 »
2007年3月 3日
ActionMailerでenvelope-fromを指定する
メールを送信する場合、ヘッダに現れるFromのほかにenvelope-fromという「本当の」送信者をしています。これはSMTPでお話しするときに指定するので、実際にMUAでメールを読むときには、表面的には現れません。最終ホップ(すなわち、local mailerに落とすMTA)がReturn-Pathというヘッダ・フィールドを付加してenvelope-fromを保存するので、かろうじてこれでみることができます。
さて、envelope-fromがどうして大事かというと、エラーが発生したときに通知するアドレスとして利用されるからです(大昔はErrors-Toなんてヘッダ・フィールドを使ってたこともありましたが、さすがにもうないでしょう)。たとえば、メーリング・リストなんかでは、エラーが実際の送信者にいってもうれしくないですし、ましてやメーリング・リスト本体に送信されちゃっても困るわけで、envelope-fromとしてはメーリング・リストの管理者にしたりするわけですね。
ところで、ActionMailerですが。こいつでメールを送信するときのenvelope-fromは自由に設定できません。こりゃこまるだろーというのが今回の話。
たとえば以下のコード。
class TestMail < ActionMailer::Base
def test1
subject "Test"
from "test-ml@example.com"
body "Please ignore."
end
end
これでTestMail.deliver_test1とかやるとメールが飛んでいくわけですが、envelope-fromはもれなくtest-ml@example.comになります。もちろんこのままでいいときもあるわけですが、多くの場合、エラーは別途処理したいと思うので、異なるアドレスをenvelope-fromに指定したいでしょう。
というわけで、以下のパッチが役に立つかも?本家にもチケットあげたので、そのうち反映されるかもしれません…が、今まで投げつけたチケットはことごとく無視されてるか、すげー反応が遅いかって感じなので、期待薄かもしれない。
Index: lib/action_mailer/base.rb
===================================================================
--- lib/action_mailer/base.rb (revision 6287)
+++ lib/action_mailer/base.rb (working copy)
@@ -36,6 +36,7 @@
# * <tt>from</tt> - Who the email you are sending is from. Sets the <tt>From:</tt> header.
# * <tt>cc</tt> - Takes one or more email addresses. These addresses will receive a carbon copy of your email. Sets the <tt>Cc:</tt> header.
# * <tt>bcc</tt> - Takes one or more email address. These addresses will receive a blind carbon copy of your email. Sets the <tt>Bcc</tt> header.
+ # * <tt>sender</tt> - Takes just one email address. This address will be used to envelope-from of SMTP and appear in <tt>Sender:</tt> header.
# * <tt>sent_on</tt> - The date on which the message was sent. If not set, the header wil be set by the delivery agent.
# * <tt>content_type</tt> - Specify the content type of the message. Defaults to <tt>text/plain</tt>.
# * <tt>headers</tt> - Specify additional headers to be set for the message, e.g. <tt>headers 'X-Mail-Count' => 107370</tt>.
@@ -315,6 +316,9 @@
# header will be set by the delivery agent.
adv_attr_accessor :sent_on
+ # Specify the Sender address for the message
+ adv_attr_accessor :sender
+
# Specify the subject of the message.
adv_attr_accessor :subject
@@ -513,6 +517,7 @@
m.to, m.from = quote_any_address_if_necessary(charset, recipients, from)
m.bcc = quote_address_if_necessary(bcc, charset) unless bcc.nil?
m.cc = quote_address_if_necessary(cc, charset) unless cc.nil?
+ m.sender = sender unless sender.nil?
m.mime_version = mime_version unless mime_version.nil?
m.date = sent_on.to_time rescue sent_on if sent_on
@@ -548,16 +553,19 @@
def perform_delivery_smtp(mail)
destinations = mail.destinations
+ sender = mail.sender(nil) || mail.from
mail.ready_to_send
Net::SMTP.start(smtp_settings[:address], smtp_settings[:port], smtp_settings[:domain],
smtp_settings[:user_name], smtp_settings[:password], smtp_settings[:authentication]) do |smtp|
- smtp.sendmail(mail.encoded, mail.from, destinations)
+ smtp.sendmail(mail.encoded, sender, destinations)
end
end
def perform_delivery_sendmail(mail)
- IO.popen("#{sendmail_settings[:location]} #{sendmail_settings[:arguments]}","w+") do |sm|
+ arguments = sendmail_settings[:arguments].dup
+ arguments += " -f#{mail.sender(nil)}" if mail.sender(nil)
+ IO.popen("#{sendmail_settings[:location]} #{arguments}","w+") do |sm|
sm.print(mail.encoded.gsub(/\r/, ''))
sm.flush
end