先提一下:针对第一篇文章,有人拍砖,值得欣慰.
原文地址:http://www.cnblogs.com/liulun/archive/2008/08/17/1269675.html
砖文地址:http://www.cnblogs.com/xiaotie/archive/2008/08/17/1269902.html
作者:兽族的荣耀
再次感谢作者
只说一句:我的目的是为了让人们熟悉一下思路知道这个系统该怎么入手,怎么做,能写出个方案来.重点不在面向对象,设计模式上
好先看代码(自认为注释的还算详细)
一:一些客户端的东西
第一个js片段
function CallServerAjax_lei()
{
//这是用div设计的模态对话筐,用于提示中间过程信息
mask.style.visibility='visible';
massage_box.style.visibility='visible'
//获取要发送的邮件的id和客户分类的id(我要把一封邮件发送给一类人)
var youjian_id = document.getElementById("<%=emailId.ClientID %>").value;
var class_id = document.getElementById("<%=DropDownList1.ClientID %>").value;
//做个初步验证
if(class_id.length <= 0)
{
alert('请选择分类');
return false;
}
//只能传一个参数,我就暂且组合了字符串,在到服务器端拆分了
var post_str = class_id + "#" +youjian_id;
//定时调用,只为了实时的显示状态信息
window.setInterval(function()
{ prepareCallServer(post_str);
},6000);
}
注意上面程序里 最后一句有个prepareCallServer函数,将在下面程序中给出
第二个js片段
function prepareCallServer(arg)
{
//这是提示信息的div
var context = document.getElementById("<%=ajax_return.ClientID %>");
CallServer(arg,context);
}
function CallServer(arg,context)
{
//一个普通的ajax回调,具体就不解释了
<%= ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context", "FalseReceiveServerData" , true)%>;
}
//回调成功后的客户端函数
function ReceiveServerData(result, context)
{
//设置实时的信息
context.innerHTML = result;
}
//回调失败后的客户端函数
function FalseReceiveServerData()
{
var context = document.getElementById("<%=ajax_return.ClientID %>");
context.innerHTML = "<IMG alt='请等待' src='load_img/loader.gif' align='center'><br>连接超时";
}
我这里写那个prepareCallServer函数貌似多余,
当时写的时候好象别有用心
现在回忆起来也惘然了.汗自己一个
二:服务器端的一些东西
先说pageload
if (!IsPostBack)
{
//每次加载页面先把线程的开始与否的标志变量重置一下
Session["SendThreadClass"] = null;
//开始判断“待发邮件数据表”里有无记录
edm_temp tempBll = new edm_temp();
//这里我写的不好,最好不要返回一个list,返回一个bool最好了(具体的不细说)
IList<edm_temp_info> temps = tempBll.GetTemp(admin_id, domain_id);
if (temps.Count >= 1)
{
ajax_return.Text = "<IMG alt='请等待' src='load_img/loader.gif' align='center'><br>开始发送上次尚未完成的邮件";
//确定要发哪封邮件
emailId.SelectedValue = temps[0].email_id.ToString();
//注册客户端事件,注意这里调用的是CallServerAjax_FalseResend();我客户端当然写了这个js方法,只是没在次文章中公布而已
Page.ClientScript.RegisterStartupScript(this.GetType(), "", "<script>CallServerAjax_FalseResend();</script>");
}
}
如果有没有发送成功的邮件,那我就直接给他发这些邮件
在看ICallbackEventHandler这个接口的实现
public void RaiseCallbackEvent(string eventArgument)
{
if (Session["SendThreadClass"] == null)
{
//初始化邮件发送实体,将在下面一段代码中提到
SendThreadClass sendobj = new SendThreadClass();
sendobj.admin_id = ((edm_admin_info)Session["logined"]).Id;
sendobj.domain_id = Convert.ToInt32(Session["domain_id"]);
//客户端传过来的字符串现在开始拆了
string[] flag_str = eventArgument.Split('#');
sendobj.arg_str = flag_str[0];
sendobj.youjian_id = Convert.ToInt32(flag_str[1]);
//以上这些就是线程函数的参数了
Thread sendmail_thread;
sendmail_thread = new Thread(new ThreadStart(sendobj.sendmail_lei));
//设置为前台线程,即使主方法执行结束了我的线程仍在执行
sendmail_thread.IsBackground = false;
sendobj.thread_flag = false;
sendmail_thread.Start();
//线程的标志变量
Session["SendThreadClass"] = sendobj;
}
}
public string GetCallbackResult()
{
//获取实时信息
int admin_id = ((edm_admin_info)Session["logined"]).Id;
int domain_id = Convert.ToInt32(Session["domain_id"]);
edm_ajax ajaxBll = new edm_ajax();
return ajaxBll.GetAjax(admin_id, domain_id);
}
}
线程的标志变量可以用bool类型的变量取代,这里我写的不好
三:最后是线程相关的类
public class SendThreadClass
{
public string arg_str;
public int admin_id;
public int domain_id;
public int youjian_id;
public bool thread_flag;
public void sendmail_lei()
{
int class_id = int.Parse(arg_str);
edm_send_mail sendmailBll = new edm_send_mail();
sendmailBll.SendMail_Lei(class_id, youjian_id,true, admin_id, domain_id);
thread_flag = true;
}
}
这里也没写什么属性,
直接把变量public了,
附件1:邮件发送逻辑层主要方法
public bool SendMail_Lei(int class_id, int email_id, bool flag, int admin_id, int domain_id)
{
bool customer_flag = false;//客户姓名标签替换哨兵变量
bool trace_flag = false;//追踪字符串哨兵变量
string mail_content = ""; //邮件正文
//先把所有的待发邮件客户插入到临时数据库中,返回客户总数。
edm_temp tempBll = new edm_temp();
int total_num = tempBll.InsertTempByClass(class_id, email_id, Convert.ToInt32(flag), admin_id, domain_id);
return true;
//把开始时间客户总数等信息存入临时AJAX数据表中,以备定时调用。
edm_ajax ajaxBll = new edm_ajax();
ajaxBll.DeleteAjax(admin_id, domain_id);
int ajax_id = ajaxBll.InsertAjax(total_num, DateTime.Now, admin_id, domain_id);
//然后在从临时数据库中取出客户信息,为了安全(高并发等等),牺牲性能!
IList<edm_temp_info> temps = tempBll.GetTemp(admin_id, domain_id);
//得到此域的SMTP信息
edm_smtp smtpBll = new edm_smtp();
edm_smtp_info smtp = smtpBll.SelectSmtp(domain_id);
//得到mail信息
edm_mail mailBll = new edm_mail();
edm_email_info email = mailBll.SelectSingleEmail(email_id);
//初始化mail组件
Mails mymail = new Mails();
mymail.From = smtp.User_Name;
mymail.FromName = smtp.From_Name;
mymail.PassWord = smtp.Pass_Word;
mymail.UserName = smtp.User_Name;
mymail.SmtpHost = smtp.Smtp;
mymail.ToName = smtp.To_Name;
mymail.Title = email.Title;
if (flag)
{
mail_content = email.Contents + "<img src='http://www.thinkedm.com/trace.aspx?A=^trace_id^' width='0' height='0' style='display:none'>";
trace_flag = true;
}
else
{
mail_content = email.Contents;
}
customer_flag = mail_content.Contains("^customer_name^");
mymail.Content = mail_content;
mymail.Files = email.Files;
//初始化邮件发送状态
edm_action_info action = new edm_action_info();
action.Admin_Id = admin_id;
action.Domain_Id = domain_id;
action.Mail_Id = email.Id;
edm_customer customerBll = new edm_customer();
edm_action actionBll = new edm_action();
action.Sort_Id = actionBll.SelectSort(domain_id)+1;
foreach (edm_temp_info temp in temps)
{
if (temp.false_num >= 3)
{
tempBll.DeleteTemp(temp.id); //如果失败了3次了!那就不客气的把这个邮件做掉
ajaxBll.UpdateSuccessAjax(ajax_id); //客户也只有暂时让他蒙在鼓里了
}
else
{
edm_customer_info customer = customerBll.selectSingleCustomer(temp.customer_id);
mymail.MailAddress = customer.E_Mail;
action.Customer_Id = customer.Id;
int trace_id = actionBll.SendAction(action);
if (trace_flag) //加入追踪id
{ mymail.Content = mymail.Content.Replace("^trace_id^", trace_id.ToString()); }
if (customer_flag) //加入客户姓名
{ mymail.Content = mymail.Content.Replace("^customer_name^", customer.User_Name); }
if (mymail.sendMail())//开始发邮件
{
tempBll.DeleteTemp(temp.id);
actionBll.SetSuccessFlag(1, trace_id);
ajaxBll.UpdateSuccessAjax(ajax_id);
}
else
{
tempBll.UpdateTemp(temp.id);
actionBll.SetSuccessFlag(0, trace_id);
ajaxBll.UpdateFalseAjax(ajax_id);
}
if (customer_flag || trace_flag)
{
mymail.Content = mail_content;
}
System.Threading.Thread.Sleep(6000);//发一封邮件休息3秒钟
}
}
return true;
}
这里有一个技巧:邮件追踪(可以得到用户在什么时间什么地点看了这个邮件)
另:发一封邮件停6秒是经验 如果是自己的SMTP服务器 估计这个时间可以短一些
附件2:返回中间过程信息的方法
public string GetAjax(int admin_id, int domain_id)
{
string load_img = "<IMG alt='请等待' src='load_img/loader.gif' align='center'><br>";
string return_str = load_img + "初始化设置开始";
float percent = 0;
edm_ajax_info ajax = dal.GetAjax(admin_id, domain_id);
edm_temp tempBll = new edm_temp();
IList<edm_temp_info> temps = tempBll.GetTemp(admin_id, domain_id);
if (temps.Count <= 0)
{
return_str = "邮件发送完成<br>" +
"共耗时:" + (DateTime.Now - ajax.start_time).TotalMinutes + "分<br>" ;
if (ajax.false_num > 0)
{ return_str = return_str + "尚有" + ajax.false_num + "封邮件未发送成功<br><a href='send_history.aspx?del_false=true' style='color:#036'>放弃失败邮件查看历史记录</a>|<span onclick='return CallServerAjax_FalseResend();' style='color:#036;cursor:hand;'>继续发送失败邮件</span>"; }
else
{ return_str = return_str + "邮件全部发送成功<br><a href='send_history.aspx' style='color:#036'>查看历史记录</a>"; }
DeleteAjax(ajax.id);
return return_str;
}
if (ajax.total_num != 0)
{
percent = (ajax.false_num + ajax.success_num) * 100 / ajax.total_num;
return_str = load_img + "邮件总数:" + ajax.total_num.ToString();
return_str = return_str + "<br>开始时间:" + ajax.start_time.ToLongTimeString();
return_str = return_str + "<br>成功数量:" + ajax.success_num.ToString();
return_str = return_str + "<br>失败数量:" + ajax.false_num.ToString();
return_str = return_str + "<br>剩余数量:" + temps.Count.ToString();
return_str = return_str + "<br>发送进度:" + percent.ToString() + "%";
}
return return_str;
}
附件3:邮件发送核心类
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Web;
using System.Net.Mail;
namespace FirGo.File
{
public class Mails
{
private string from;
private string fromName;
private string userName;
private string passWord;
private string smtpHost;
private string title;
private string content;
private string mailaddress;
private string toname;
private string files;
public string From
{
set { from = value; }
}
public string FromName
{
set { fromName = value; }
}
public string UserName
{
set { userName = value; }
}
public string PassWord
{
set { passWord = value; }
}
public string SmtpHost
{
set { smtpHost = value; }
}
public string Title
{
set { title = value; }
}
public string Content
{
set { content = value; }
get { return content;}
}
public string MailAddress
{
set { mailaddress = value; }
}
public string ToName
{
set { toname = value; }
}
public string Files
{
set { files = value; }
}
public Mails()
{
}
//暂时不用asp.net组件发邮件,因为有的邮箱不太喜欢这个
public bool sendMail()
{
MailMessage messages = new MailMessage();
messages.From = new MailAddress(from, fromName);
messages.To.Add(new MailAddress(mailaddress));
messages.Subject = title;
messages.SubjectEncoding = System.Text.Encoding.Default;
messages.Body = content;
messages.BodyEncoding = System.Text.Encoding.Default;
messages.IsBodyHtml = true;
messages.Priority = MailPriority.High;
//不能使用这个try块,想要有附件的时候没有附件问题就大了
//try
//{
if (!string.IsNullOrEmpty(files))
{
Attachment fujian = new Attachment(files);
messages.Attachments.Add(fujian);
}
//}
//catch
//{ }
SmtpClient client = new SmtpClient(smtpHost);
NetworkCredential smtpuserinfo = new NetworkCredential();
smtpuserinfo.UserName = userName;
smtpuserinfo.Password = passWord;
client.Credentials = smtpuserinfo;
client.Timeout = 36000000;
//try
//{
client.Send(messages);
//}
//catch
//{ return false; }
messages.Dispose();
return true;
}
}
}
写到这里代码还是不全,
不过到此为止吧,如果尚有不明白的地方,
请在下面留言提问,
我会及时回复的
另:有些大侠看见了我写的东西估计要鄙视一下了,什么OO啊,什么模式啊都没用
其实这个项目根本就没写需求分析,没画这个图那个图的
最初只是为了给某网站开发一个邮件反馈功能
后来他们觉得好用,说我要加钱,给我弄成自动反馈的.
后来有觉得好用,说我们要邮件营销,能不能给我们弄成群发的,
我汗,然后就这样了