论坛首页 编程语言技术论坛

ActionMailer发送大量邮件(ar_mailer hacks)

浏览 6763 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2006-12-09  
Hack ar_mailer
前面说到使用rails发送邮件的问题,问题还没完,遇到大量邮件发送的时候,ActionMailer就处理不过来了。其实不用大量邮件发送,使用gmail发送邮件的时候反应也比较慢,怎么办呢?还好找到了一个叫ar_mailer的插件(在rubyforge上的rctool项目下)。

ar_mailer的思想其实很简单,就是你要发送邮件吧,好,我不管你发多少封,我把你的发件人、收件人、邮件内容全部存到数据库里,相当于一个队列,然后慢慢一封一封地发。这样就不会连半天服务器连不上结果发信失败了。而且这样有一个好处,用户那里反应很快,因为只有一个数据库操作的时间,这往往比连smtp服务器特别是远程的smtp服务器快多了。

好,我们就要使用ar_mailer了。首先按照文档里说的
ruby 代码
  1. gem install ar_mailer  

然后cd到我的rails项目目录下
ruby 代码
  1. ar_sendmail --create-migration  
  2. ar_sendmail --create-model  

然后把新建的Email那个model里面的class Emailer < ActionMailer::Base改成class Emailer < ActionMailer::ARMailer,然后在environment.rb里面加一句ActionMailer::Base.delivery_method = :activerecord
好了,可以运行ar_sendmail了,咦?怎么不成功?

我想在windows平台下,可能跟linux的环境有所区别,于是开始看原因。
我这里有几个问题(可能不会在所有地方都出现,也许有的是我误操作)
1.找不到ar_sendmail。这个好解决,把ar_mailer的文件都拷到action_mailer目录下。(比如我的就是把D:\InstantRails\ruby\lib\ruby\gems\1.8\gems\ar_mailer-1.1.0\lib\action_mailer下的ar_mailer.rb和ar_sendmail.rb拷贝到D:\InstantRails\ruby\lib\ruby\gems\1.8\gems\actionmailer-1.2.5\lib\action_mailer下)
2.数据库没有建立成功。我对migration不怎么会,于是就自己手工创建了,建了个emails表,ddl如下:
sql 代码
 
  1. CREATE TABLE `emails` (  
  2.   `id` int(10) unsigned NOT NULL auto_increment,  
  3.   `fromvarchar(255) NOT NULL,  
  4.   `tovarchar(255) NOT NULL,  
  5.   `last_send_attempt` int(10) unsigned NOT NULL default '0',  
  6.   `mail` text NOT NULL,  
  7.   PRIMARY KEY  (`id`)  
  8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8  

总结一下,要做的事情:
1.安装ar_sendmail
2.创建emails表
3.创建Email这个Model
4.将从ActionMailer继承的Mailer改成从ARMailer继承(比如我的Mailer叫Notifier)
5.在environment.rb里面加上一句ActionMailer::Base.delivery_method = :activerecord,对了,原来的ActionMailer::Base.delivery_method = :msmtp可以去掉了
6.在rails项目的目录下运行ar_sendmail

好了,这下应该ok了吧,嗯,还是不行。。。仔细一看错误提示,发现ar_mailer还是用的smtp发信,去找本地邮件服务器。但是俺用的是gmail,咋办呢,动手hack吧。

其实ar_mailer这个plugin就2个文件,ar_mailer.rb和ar_sendmail.rb。我主要是要改发信机制的地方,就改ar_sendmail.rb了。

找到ar_sendmail.rb中的deliver方法
ruby 代码
 
  1. def deliver(emails)  
  2.     Net::SMTP.start server_settings[:address], server_settings[:port],  
  3.                     server_settings[:domain], server_settings[:user],  
  4.                     server_settings[:password],  
  5.                     server_settings[:authenticationdo |smtp|  
  6.       until emails.empty? do  
  7.         email = emails.shift  
  8.         begin  
  9.           res = smtp.send_message email.mail, email.from, email.to  
  10.           email.destroy  
  11.           log "sent email %011d from %s to %s: %p" %  
  12.                 [email.id, email.from, email.to, res]  
  13.         rescue Net::SMTPFatalError => e  
  14.           log "5xx error sending email %d, removing from queue: %p(%s):\n\t%s" %  
  15.                 [email.id, e.message, e.class, e.backtrace.join("\n\t")]  
  16.           email.destroy  
  17.           smtp.reset  
  18.         rescue Net::SMTPServerBusy, Net::SMTPUnknownError,  
  19.                Net::SMTPSyntaxError, TimeoutError => e  
  20.           email.last_send_attempt = Time.now.to_i  
  21.           email.save rescue nil  
  22.           log "error sending email %d: %p(%s):\n\t%s" %  
  23.                 [email.id, e.message, e.class, e.backtrace.join("\n\t")]  
  24.           smtp.reset  
  25.         end  
  26.       end  
  27.     end  
  28.   end  

看,用的Net::SMTP吧,好,我只需要调用msmtp就好了,改成这样:
 
ruby 代码
 
  1. def deliver(emails)  
  2.      until emails.empty? do  
  3.          email = emails.shift  
  4.          IO.popen("d:\\msmtp -t -C d:\\.msmtprc -a gmail --""w"do |sm|  
  5.            sm.puts(email.mail.gsub(/\r/, ''))  
  6.            res = sm.flush  
  7.            email.destroy  
  8.            log "sent email %011d from %s to %s: %p" %  
  9.                  [email.id, email.from, email.to, res]  
  10.          end  
  11.      end  
  12. end  


好了,可以发送邮件了,邮件多也不会把服务器压垮了,哈哈。当然,现在还有几个问题:
1.没有控制出错(我对ruby的异常机制不了解:P)。如果出错了,ar_mailer就会退出,然后我再重启一下ar_sendmail,反正没发送成功的邮件没有destroy。
2.ar_mailer一直运行,监控邮件发送。在linux下ar_sendmail &就好了,他自己运行,我就可以退出了。但是在windows下就得开一个命令行,让他一直跑着。有点丑陋,而且容易出意外。我试了下把ar_mailer装成一个服务,但是启动不了。如果能像mongrel_service那样就好了,这个,就只能等高手出招了。
   发表时间:2007-02-12  
如果用它发送HTML的MAIL呢,以及附件?
0 请登录后投票
   发表时间:2007-02-12  
html的没有问题,发送word附件没搞定,附件编码老是有问题,之后就没弄了。
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics