11 March 2015

前言

仔细想想,关于邮件发送的任务也是从年前拖到了年后。看样子拖不下去了,我这周要将其搞定收工。然后,腾出手来做其他的事情。

正文

我觉得,一个项目迭代了两年,就会存在各种各样的”垃圾”,比如,发送邮件存在xx种形式。针对邮件的功能,在项目中做了一番调查:

  • mailchimp-api
  • resque_mailer
  • Action Mailer
  • SendCloud

备注: 邮件的事情,咨询了相关人之后,得知mailchimp-api可能就不需要了。

Rails 使用 Action Mailer实现邮件发送,邮件程序和视图,ActionMailer::Base,与控制器类似,app/mailersapp/views,简单的例子程序如下:

class UserMailer < ActionMailer::Base
  default from: 'notifications@example.com'

  def welcome_email(user)
    @user = user
    @url = 'http://example.com/login'
    mail(to: @user.email, subject: 'Welcome to My Awesome Site')
  end
end

邮件程序不知道请求的上下文,需要指定host,使用xxx_url,或使用url_for时,指定only_path: false

Action Mailer中也可设置before_actionafter_actionaround_action这些过滤器。

Action Mailer继承自AbstractController,控制器中的帮助方法均可使用。

Mailer选项最好在环境相关的文件(environment.rb, production.rb)中进行配置。

注册以及验证邮箱之类,通过Rails自带的ActionMailer程序进行发送的,

sendcloud

向用户批量发送邮件使用的第三方的服务 - sendcloud,发送使用了其web api的方式,使用的sendcloud类是自定义的。

在github上搜了一下,sendclound的相关的ruby项目还挺多的。大概有5个。

调用方式: SMTP和WEBAPI(支持HTTPS)。

操作流程:

  • 写程序,调接口,传数据
  • 请求成功,数据处理( 排队调度, 速率控制, 变量替换, 追踪 )
  • 处理结束,发送邮件( outbound )
  • outbound投递邮件

邮件类型: 触发和批量

API_USER: 调用接口发信的帐号,具有类型、发信域名、追踪选项等

API_KEY: 可重置,可共用

发信域名: 配置VERIFY_KEYSPFMXCNAMEDKIM。感觉好复杂。

看了好多天,没实在感,找了个方式测试一下:

RestClient.post "https://sendcloud.sohu.com/webapi/mail.send.json",
                :api_user => "xxx",
                :api_key => "xxxx",
                :from => "no-reply@tophold.com",
                :fromname => "天厚投资",
                :to => "xiajian@tophold.com",
                :subject => "测试",
                :html => "这是一个测试"

执行了一下,居然成功了,看到效果,有了继续下去的操作勇气。又定义了一个获取列表的函数,并发现一个问题,API文档 中描述可以使用get请求,实际上是使用get请求列表的返回结果如下:

{"message":"error","errors":["Bad username / password!"]}

而post请求却是正常的,仔细想想,使用get请求存在诸多的不安全性,api_userapi_key很容易被抓包。

备注: 找到了一个关于sendcloud的gem包,正在由于是用自制的还是使用gem包。感觉上gem包要复杂些,自写的重复代码太多。

搞了半天,结果发送一周未登录的邮件居然不是通过sendcloud发送的,坑爹啊。

编写邮件view的注意点:

  • 所有的url必须是绝对地址
  • 所有的样式必须是直接写在body中。

smtp的配置

配置使用smtp的服务,代发所有的邮件,最重要的就是smtp的配置。下面列出一些配置:

官方给出的配置:

Mail.defaults do                                                                
    delivery_method :smtp, {                                                       
        :address   => "smtpcloud.sohu.com",                                     
        :port      => 25,                                                       
        :user_name => "api_user",                     
        :password  => "api_key",                                          
        :authentication => 'login'                                                 
    }                                                                              
end

自己使用的配置:

ActionMailer::Base.smtp_settings = {
  :address => "smtpcloud.sohu.com",
  :port => 25,
  :authentication => :login,
  :domain => 'tophold.com',
  :user_name => "xxx",
  :password => "xxx"
}

就这个简单的配置,拖了好几个月。

遇到问题

An SMTP From address is required to send a message. Set the message smtp_envelope_from, return_path, sender, or from address.

搞了半天,才知道是修改问题后,Rake任务不自动加载代码,然后,我就一直在纠结为何总是发不出去,最后问了前辈之后,才知道为何。重启了一下,就好。唉,又一个上午没有了。不过,对如何发送和测试邮件有了整体的思路,以后再做相关的工作,就轻松了,测试果然太重要了。

启动后台邮件任务: rake resque:work QUEUE="async_mailer" ,在redis中生成了名为”resque:tophold:queue:async_mailer”的list类型,其中resque:tophold是所谓的命名空间。

测试发送邮件:

u = User.where( email: "xxx@qq.com").first
NoticeMailer.login(u.id).deliver               # 邮件的发送,需要使用deliver方法,login是邮件控制器的动作

此刻,我对如何使用和启动后台任务,有了更加深入的的了解,并且,有了可评估和测试的环境,感觉相当不错。

针对全体用户发送邮件,qq链接邮件种类的问题(qq连接的用户邮件根本发不出去)。

查询后发现,已有用户中,居然有39808个用户是通过qq授权,且未验证邮箱的。然后,未验证的邮箱发送的结果就是这样的。

错误的邮件地址请求

sendcloud一直将xx@example.com这种类型邮件地址设置为请求状态,我把这个问题向sendcloud的客服反馈了一下,敲字敲到手疼。

mail的视图,不能使用视图的辅助方法,只能使用图片的绝对路径,这是硬伤。

后记

近来,觉得自己十分的平庸,干啥啥不成。因为又有一件事情干到一半,然后放在一边了,比如邮件的这次任务。

我觉得,我这种性格还是有一定的好处的,犹如单核多进程一般的,乱序执行,话说,进程间切换开销很大的说。

被市场部的追着要邮件发送的功能了,拖不下去了。这个邮件召回的任务,我拖了3个月,有没有很牛叉的感觉。

我觉得,邮件系统这件事,还是很有搞头的。 而且,我觉得我做的这件事情,重复的太多,一点都不最佳实践,但是,自己也没有作出什么更好的改进。




傲娇的使用Disqus