详解Asp.Net定时发送邮件方法
用.net发送邮件,总结起来有以下那么三种:
(1)做一个winform 来定时发邮件。然后通过windows计划任务,设置为指定时间,每次自动运行,运行完毕后自动关闭。
(2)用sqlserver 数据库实现发邮件,用sqlserver实现发邮件的存储过程,然后制定一个作业,制定时间运行。
(3)在 Global.asax 文件里编程。事件:Application_Start。利用Time类编程。比如服务器1秒钟执行一次判断。
在编程之前,先介绍一下 Global.asax文件里的几个方法。
protected void Application_Start(Object sender, EventArgs e)
{
//Application_start方法:请求 ASP.NET 应用程序中第一个资源(如页)时调用。在应用程序的生命周期期间仅调用一次
}
protected void Application_End(Object sender, EventArgs e)
{
//Application_end方法:在卸载应用程序之前对每个应用程序生命周期调用一次。
}
下面是具体的做法:
代码
protected void Application_Start(Object sender, EventArgs e)
{
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)
{
if (GetEmailContent.GetMailContent().Length == 0)
{
return;//如果没有通过三审的订单要发送,则返回不发送邮件
}
欢迎进入.NET社区论坛,与200万技术人员互动交流 >>进入
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邮箱都可以实现发送邮件的功能,大家可否讨论下他们是怎样实现的。
摘自红色黑客联盟(www.7747.net) 原文:http://www.7747.net/kf/201009/73942.html
附:
附2:
正确配置和使用SQL mail
使用SQL Mail收发和自动处理邮件中的扩展存储过程简介
SQL SERVER提供了通过EXCHANGE或OUTLOOK收发邮件的扩展存储过程,下面将这几个过程简单的介绍一下。
一、启动SQL Mail
xp_startmail @user,@password
@user和@password都是可选的
也可打开Enterprise Manager中的Support Services,在SQL Mail上单击右键打开右键菜单,然后按Start来启动
二、停止SQL Mail
xp_stopmail
也可用上述方法中的菜单里的Stop来停止
三、发送邮件
xp_sendmail {[@recipients =] 'recipients [;...n]'}
[,[@message =] 'message>
[,[@query =] 'query>
[,[@attachments =] attachments]
[,[@copy_recipients =] 'copy_recipients [;...n]'
[,[@blind_copy_recipients =] 'blind_copy_recipients [;...n]'
[,[@subject =] 'subject>
[,[@type =] 'type>
[,[@attach_results =] 'attach_value>
[,[@no_output =] 'output_value>
[,[@no_header =] 'header_value>
[,[@width =] width]
[,[@separator =] 'separator>
[,[@echo_error =] 'echo_value>
[,[@set_user =] 'user>
[,[@dbuse =] 'database>
其中@recipients是必需的
参数说明:
参数 说明
@recipients 收件人,中间用逗号分开
@message 要发送的信息
@query 确定执行并依附邮件的有效查询,除触发器中的插入表及删除表外,此查询能引用任何对象
@attachments 附件
@copy_recipients 抄送
@blind_copy_recipients 密送
@subject 标题
@attach_results 指定查询结果做为附件发送
@no_header 不发送查询结果的列名
@set_user 查询联接的用户名,默认为Guset
@dbuse 查询所用的数据库,默认为缺省数据库
四、阅读邮件收件箱中的邮件
xp_readmail [[@msg_id =] 'message_number> [, [@type =] 'type' [OUTPUT]]
[,[@peek =] 'peek>
[,[@suppress_attach =] 'suppress_attach>
[,[@originator =] 'sender' OUTPUT]
[,[@subject =] 'subject' OUTPUT]
[,[@message =] 'message' OUTPUT]
[,[@recipients =] 'recipients [;...n]' OUTPUT]
[,[@cc_list =] 'copy_recipients [;...n]' OUTPUT]
[,[@bcc_list =] 'blind_copy_recipients [;...n]' OUTPUT]
[,[@date_received =] 'date' OUTPUT]
[,[@unread =] 'unread_value' OUTPUT]
[,[@attachments =] 'attachments [;...n]' OUTPUT])
[,[@skip_bytes =] bytes_to_skip OUTPUT]
[,[@msg_length =] length_in_bytes OUTPUT]
[,[@originator_address =] 'sender_address' OUTPUT]]
参数说明:
参数 说明
@originator 发件人
@subject 主题
@message 信息
@recipients 收件人
@skip_tytes 读取邮件信息时跳过的字节数,用于顺序获取邮件信息段。
@msg_length 确定所有信息的长度,通常与@skip_bytes一起处理长信息
五、顺序处理下一个邮件
xp_findnextmsg [[@msg_id =] 'message_number' [OUTPUT]]
[,[@type =] type]
[,[@unread_only =] 'unread_value> )
六、删除邮件
xp_deletemail {'message_number'}
如果不指定邮件编号则删除收件箱中的所有邮件
七、自动处理邮件
sp_processmail [[@subject =] 'subject>
[,[@filetype =] 'filetype>
[,[@separator =] 'separator>
[,[@set_user =] 'user>
[,[@dbuse =] 'dbname>
>用户在网上注册后,系统将随机产生的密码发送到用户登记的Email
>用户在论坛的帖子有回复时将内容发送到用户的Email
因为上述过程都是在存储过程中完成的,所以避免了前台程序对参数的传输处理,也不需要再用第三方的组件完成,感觉比较方便。
1.为了使用SQL mail,首先你的服务器上得有SMTP服务,我没有安装win2000 server自带的SMTP,而是用imail6.04的SMTP,感觉比较稳定,功能也比较强。
2.安装一个邮件系统,我安装了outLook 2000,我发现在配置邮件profile时,如果
不安装outLook而是用别的第三方程序,win2k中文server版在控制面板中就找不到“邮件”一项.
3.安装完outlook后再刷新控制面板,就会找到“邮件”一项,双击进行邮件的配置,为配置文件起一个名字(假设为myProfile),以便以后SQL mail使用,在该配置文件中设置各项属性。
4.启动outlook(设置为用myProfile作为默认的配置文件),测试进行收发邮件,确认outlook工作正常。
5.用当前的域帐户启动SQL server,在企业管理器的支持服务中,点击SQL mail的属性,可以看到在配置文件选择中,出现了刚才定义的myProfile配置文件(你也可以定义多个profile),选择这个配置文件进行测试,SQL将返回成功开始和结束一个MAPI会话的信息,如果出现错误或是没有找到邮件配置文件,那一定是你启动SQL server用的帐号有问题
6.现在你就可以在查询分析器中用XP_sendmail这个扩展存储过程发送SQL mail了,格式如下:
xp_sendmail {[@recipients =] 'recipients [;...n]'}
[,][@message =] 'message>
[,][@query =] 'query>
[,][@attachments =] attachments]
[,][@copy_recipients =] 'copy_recipients [;...n]'
[,][@blind_copy_recipients =] 'blind_copy_recipients [;...n]'
[,][@subject =] 'subject>
[,[@type =] 'type>
[,][@attach_results =] 'attach_value>
[,][@no_output =] 'output_value>
[,][@no_header =] 'header_value>
[,][@width =] width]
[,][@separator =] 'separator>
[,][@echo_error =] 'echo_value>
[,][@set_user =] 'user>
[,][@dbuse =] 'database>
其中@recipients是必需的
参数说明:
参数 说明
@recipients 收件人,中间用逗号分开
@message 要发送的信息
@query 确定执行并依附邮件的有效查询,除触发器中的插入表及删除表外,此查询能引用任何对象
@attachments 附件
@copy_recipients 抄送
@blind_copy_recipients 密送
@subject 标题
@attach_results 指定查询结果做为附件发送
@no_header 不发送查询结果的列名
@set_user 查询联接的用户名,默认为Guset
@dbuse 查询所用的数据库,默认为缺省数据库
7.不过,如果是在web应用中使用SQL mail,还有一些问题要解决:首先,就是应用程序中连接数据库的帐号,我在网站程序中的数据库连接是使用UDL文件,帐号为DbGuest,这是一个普通帐户,所以还必须在master库的扩展存储过程找到XP_sendmail,并在其属性中增加DbGuest这个用户,并选择EXEC权限。
好了,现在设置完毕,运行网站程序,测试用户注册,几乎没有什么延迟,我测试用的邮箱中就收到了这封SQL mail发出的Email:
"谢谢你的注册,建议你首次登录后修改密码"