深入ActionMailer,使用Sendmail发邮件

本文介绍了Rails框架中ActionMailer组件的邮件发送原理,包括SMTP和Sendmail两种发送方式的配置及实现细节,并探讨了为何仅支持这两种方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ActionMailer现在的实现只支持smtp和Sendmail两种方式发送邮件,配置分别如下:
Java代码 复制代码

1. # ActionMailer::Base.delivery_method = :smtp
2. # ActionMailer::Base.smtp_settings = SMTP_SETTINGS
3. ActionMailer::Base.delivery_method = :sendmail
4. ActionMailer::Base.sendmail_settings = SENDMAIL_SETTINGS
5. SMTP_SETTINGS = {
6. :address => "smtp.gmail.com",
7. :port => 587,
8. :domain => "beyondrails.com",
9. :authentication => :login,
10. :user_name => "beyondrails@gmail.com",
11. :password => "password"
12. }
13. SENDMAIL_SETTINGS = {
14. :location => '/usr/sbin/sendmail',
15. :arguments => '-i -t'
16. }

# ActionMailer::Base.delivery_method = :smtp
# ActionMailer::Base.smtp_settings = SMTP_SETTINGS
ActionMailer::Base.delivery_method = :sendmail
ActionMailer::Base.sendmail_settings = SENDMAIL_SETTINGS
SMTP_SETTINGS = {
:address => "smtp.gmail.com",
:port => 587,
:domain => "beyondrails.com",
:authentication => :login,
:user_name => "beyondrails@gmail.com",
:password => "password"
}
SENDMAIL_SETTINGS = {
:location => '/usr/sbin/sendmail',
:arguments => '-i -t'
}


为什么只支持这两种方式呢?让我们看下ActionMailer::Base的源码:
Java代码 复制代码

1. module ActionMailer
2. class Base
3. class << self
4. def method_missing(method_symbol, *parameters)#:nodoc:
5. case method_symbol.id2name
6. when /^create_([_a-z]\w*)/ then new($1, *parameters).mail
7. when /^deliver_([_a-z]\w*)/ then new($1, *parameters).deliver!
8. when "new" then nil
9. else super
10. end
11. end
12. end
13. def deliver!(mail = @mail)
14. raise "no mail object available for delivery!" unless mail
15. logger.info "Sent mail:\n #{mail.encoded}" unless logger.nil?
16. begin
17. send("perform_delivery_#{delivery_method}", mail) if perform_deliveries
18. rescue Exception => e # Net::SMTP errors or sendmail pipe errors
19. raise e if raise_delivery_errors
20. end
21. return mail
22. end
23. private
24. def perform_delivery_smtp(mail)
25. destinations = mail.destinations
26. mail.ready_to_send
27.
28. Net::SMTP.start(smtp_settings[:address], smtp_settings[:port], smtp_settings[:domain],
29. smtp_settings[:user_name], smtp_settings[:password], smtp_settings[:authentication]) do |smtp|
30. smtp.sendmail(mail.encoded, mail.from, destinations)
31. end
32. end
33.
34. def perform_delivery_sendmail(mail)
35. IO.popen("#{sendmail_settings[:location]} #{sendmail_settings[:arguments]}","w+") do |sm|
36. sm.print(mail.encoded.gsub(/\r/, ''))
37. sm.flush
38. end
39. end
40. end
41. end
42. end

module ActionMailer
class Base
class << self
def method_missing(method_symbol, *parameters)#:nodoc:
case method_symbol.id2name
when /^create_([_a-z]\w*)/ then new($1, *parameters).mail
when /^deliver_([_a-z]\w*)/ then new($1, *parameters).deliver!
when "new" then nil
else super
end
end
end
def deliver!(mail = @mail)
raise "no mail object available for delivery!" unless mail
logger.info "Sent mail:\n #{mail.encoded}" unless logger.nil?
begin
send("perform_delivery_#{delivery_method}", mail) if perform_deliveries
rescue Exception => e # Net::SMTP errors or sendmail pipe errors
raise e if raise_delivery_errors
end
return mail
end
private
def perform_delivery_smtp(mail)
destinations = mail.destinations
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)
end
end

def perform_delivery_sendmail(mail)
IO.popen("#{sendmail_settings[:location]} #{sendmail_settings[:arguments]}","w+") do |sm|
sm.print(mail.encoded.gsub(/\r/, ''))
sm.flush
end
end
end
end
end


我们可以清楚的看到ActionMailer的调用顺序,首先是method_missing捕捉deliver_xxx方法,然后进入deliver!方法,然后根据deliver_method进入perform_deliver_xxx方法。

可以看到,sendmail方式的实现也非常简单,直接使用IO.popen方法来调用系统命令。
使用Sendmail这一Linux下高性能邮件服务器发送邮件,可以避免使用Gmail等邮件系统提供的smtp服务不稳定或需要Recaptcha图片验证等麻烦问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值