asp.net定时发送邮件总结
香港那边公司的市场部开会时要求我们这边实现一个定时发送邮件的功能,即在每天下午5点左右定时把今天已通过三审的订单信息发给市场部的经理,告诉他哪些订单已经通过了终审。平时只知道如何用.net发送邮件,但不知如何定时发送邮件。于是百度了一下,总结起来有以下那么三种:
(1)做一个winform 来定时发邮件。然后通过windows计划任务,设置为指定时间,每次自动运行,运行完毕后自动关闭。
(2)用sqlserver 数据库实现发邮件,用sqlserver实现发邮件的存储过程,然后制定一个作业,制定时间运行。
(3)在 Global.asax 文件里编程。事件:Application_Start。利用Time类编程。比如服务器1秒钟执行一次判断。
香港那边的公司的ERP糸统是BS模式,由于对方公司服务器环境条件与解决方案要简单的限制,我和我师傅决定用第三种方法。在编程之前,先介绍一下Global.asax文件里的几个方法。
下面是具体的做法:
{
Timer t = new Timer(60000);//设计时间间隔,如果一个小时执行一次就改为3600000 ,这里一分钟调用一次
t.Elapsed += new ElapsedEventHandler(t_Elapsed);
t.AutoReset = true;
t.Enabled = true;
}
private void t_Elapsed(object sender, ElapsedEventArgs e)
{
{
return;//如果沒有通過三審的訂單要發送,則返回不發送郵件
}
int sendTime_Hour = Convert.ToInt32(ConfigurationManager.AppSettings["SendTime"].ToString());//假如是下午17:00分发送
int now_Hour = Convert.ToInt32(DateTime.Now.Hour.ToString());
int now_Minute = Convert.ToInt32(DateTime.Now.Minute.ToString());
int absolute = 1;//差距值,單位為分鐘
if (((now_Hour == sendTime_Hour - 1) && (now_Minute >= 60 - absolute)) || ((now_Hour == sendTime_Hour) && (now_Minute <= absolute))) //即在如果时间判断是落在16:59分至17:01分之间,那么就会调用下面的邮件发送方法
string subject = string.Format("CO Approve Report({0})", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
string host = ConfigurationManager.AppSettings["MailHost"];
string from = ConfigurationManager.AppSettings["MailFrom"];
string to = ConfigurationManager.AppSettings["MailTo"];
string user = ConfigurationManager.AppSettings["MailUser"];
string password = ConfigurationManager.AppSettings["MailPassword"];
string content = GetEmailContent.GetMailContent();
try
{
OrderMail.Send(host, user, password, to, from, subject, content, null);//发送邮件的方法,改为你自己的邮件发送方法
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
}
如果一定要确精到分,可以设置相距时间为秒级,以及设置定时器的时间间隔为秒级,比如一秒调用一次t_Elapsed,但必须符合的一件条件是:定时器的时间间隔<=2*absolute,absolute为差距值,见上面黄色背景的定义,具体多少以客户的要求为准,不满足这个条件的话不能实现在规定的时间段内调用邮件发送的方法。
好,代码编写完毕,测试没问题,下班再设置晚上9点收到邮件(理论值应是8点59至9点1分之间收到),当天发现没收到邮件,问题来了!为什么在上班的测试没问题,但下班后9点没收到邮件?网上查了一下,发觉自己还有个问题没考虑到:Application对象是有生命周期的,当网页没人访问或闲置过久,应用程序池会调用Application_End方法回收applicatioin里的对象资源,导致定时器无法工作。
解决方法:在IIS6.0以上版本设置IIS应用程序池的回收时间,默认好像是20分钟,可设置长一些,但不要太长,否则有可能出现网站假死的现象。当晚再测试,可以正式发送邮件!起码到现在已经用了两三个月,都能正常定时发送邮件。IIS5.0没有应用程序池,可以在C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\ machine.config里面设置,具体设置可以参照:http://www.zhiweinet.com/jiaocheng/2008-07/1145.htm
还有,对于Applicatioin_Start方法,有很多人都会产生一个误解: Application_Start是第一个人访问网站时加载的,只会调用一次,以后都不会调用;Application_Start是第一个人访问网站时加载的,这个没错,前提是在它的生命周期内,有以下几个原因也会导致应用程序池重新启动, 即Application_Start可以再次被调用:
1)添加、修改或删除应用程序的 Bin 文件夹中的程序集。
2)添加、修改或删除 App_GlobalResources 或 App_LocalResources 文件夹中的本地化资源。
3)添加、修改或删除应用程序的 Global.asax 文件。
4)添加、修改或删除 App_Code 目录中的源代码文件。
5)添加、修改或删除配置文件配置。
6)添加、修改或删除 App_WebReferences 目录中的 Web 服务引用。
7)添加、修改或删除应用程序的 Web.config 文件。
附应用程序生命周期概述:http://www.cnblogs.com/adsiz/archive/2008/01/17/1042746.html
附.NET垃圾回收机制 :http://blog.csdn.net/lerit/archive/2009/08/16/4451287.aspx
附SqlServer发送邮件解决方法:http://www.cnblogs.com/yjmyzz/archive/2008/09/04/1284229.html
在正常情况下Application_Start只调用一次,这样就不会实例化无数个定时器而占用服务器的资源 ,还有个问题是定时器的时间间隔如果精确到秒级的话是否会占用很多的内存,吃内存是肯定会的,所以要根据具体的情况设置应用程序池的回收时间和加大定时器设定的时间间隔。
上面定时发送邮件的解决方法只是我个人的做法,可供参考,不见得是最好的方法。因为对方公司的糸统是内部访问,访问量很小,所以性能方面要求没有多大关糸,对方到现在也没反映过性能方面的问题,但我觉得肯定有其他更好但又容易实施的解决方法,QQ邮箱与163邮箱都可以实现发送邮件的功能,大家可否讨论下他们是怎样实现的。