一般的行业网站多会有邮件发送需求,如注册确认,用户信息提醒,生日问候等.
为保证伸缩性将邮件发送模块独立布置成一个站点(MailWeb),发送放使用WebServices的方式通知MailWeb进行发邮件操作. MailWeb上的邮件发送组件根据需要发送邮件数目的量,分配线程进行相应发送操作, 而发送站点只要将要发送的邮件写入数据库后发一个发送通知给MailWeb. 这样一方面提高调用方的响应速度,另一方面可以根据实际情况给MailWeb站点分配资源,使系统具备了伸缩性,也统一了邮件发送的处理.
邮箱帐号轮流选择
为提高邮件到达率(减少垃圾邮件数量),这里采用第三方邮件服务发送(如QQ,163等),QQ邮箱支持SMTP发送,不过每天只能发30封, 一般网站一天可能有百来封信件要发,那么你可以注册多个QQ号, 发送时随机取出一个帐号进行发送操作,当然也可以给每个帐号分配一个计数器,每发一封将将对应计数器加一,每次取计数器数值最小的帐号来发送,然后累加一,这样就可以保证绝对平均了.
统一邮件发送人信息
使用SmtpClient发邮件时如果没设置MailMessage.From属性的display属性那么用户收到邮件后将显示发件人的email地址(多数情况下是英文),当你使用多个帐号轮流发送时用户收到的邮件发送人一栏的显示将很混乱,所以应该使用下面的方式来设置:
//-----------------------------------
MailMessage message = new MailMessage();
message.To.Add(To);
message.From = new MailAddress(From,"魔兽帐号交易网");
....
//---------------------------------------
经过上面设置后,不管使用那个帐号,系统发出去的邮件用户名将统一显示为"魔兽帐号交易网".
设计数据表
数据库主要包括Email表(EmailId,主题,内容,模板号,添加时间,优先级别,....)
Sending表(EmailId,Priority,State,SendCount,LasthandleTime...)这个表主当发送队列来使用,并安排清理工作调度每天将处理过的数据更新到Email表,并删除.这样就能保证Sending表的体积始终在一般现在的范围内.
State: 0未处理,1发送中,2发送成功,3发送失败,4死邮件
加载需要发送的信件存储过程,需要在程序里保证,这个存储过程是在通过同步方式访问的(只有一个线程在调用对应方法)
必要时可以使用进程同步方式,如邮件服务组件分别配置在Windows服务与IIS站内.
//===================
Create table #t (id int)
Insert Into #t(id)
Select top 300 MailId From [Sending] Where
(state=0 Or state=3)
Order By Priority, MailId desc --按发送优先级排序
--更新发件表状态
Update [Sending] set State=1 From
Sending inner join [#t] on [#t].id=Sending.MailId
Select Sending.* From Sending inner join [#t] On [#t].id=Sending.MailId
Order by Sending.Priority asc
Drop Table #t
//=======================
邮件发送组件设计
一个主线程序程序在接到通知时访问Sending表,加载需要发送的邮件(最多300条,另外考虑同步问题),根据加载的邮件集合中邮件数量多少,分配1-N个线程去执行发送,注意不要将上限N设的过高,那样将达不知道资源控制的目的.