邮件群发工具的编写

--------------------------------------------------------------------------------

第一步:邮箱批量采集器的制作。

    邮箱批量采集,要选择好采集的页面,我在这里就选择163邮箱吧。因为这种页面采集比较中规中矩。

看出什么来了吗?对,这个页面全部是163会员的信息。其中这个页面的html文本里面还有我们要找的邮箱资料。

 

红框里面的就是我们要找的邮箱地址的“base64字符串格式”,只要提取出来后,将其变化为普通的文本就可以了,这在.net里很好解决。

下面的要做事就是用http嗅探器抓取参数资料了。这一步就直接省略...

接下来就直接贴上代码了。

 
View Code  
  5 //
  6 using System;
  7 using System.Collections.Generic;
  8 using System.Linq;
  9 using System.Text;
 10 using System.Web;
 11 using System.Text.RegularExpressions;
 12 using System.Net.Mail;
 13 using System.Net;
 14 namespace System
 15 {  //邮箱提取控制类
 16    public class MailUtil
 17     {
 18         public int Index { get; set; }
 19         public int Type { get; set; }
 20         public string Gender { get; set; }
 21         public string Online { get; set; }
 22         public string Province { get; set; }
 23         public string City { get; set; }
 24         public bool HasNext { get; set; }
 25         #region 构造函数
 26         public MailUtil()
 27         {
 28             this.Init(1, 5, "", "", "", "");
 29         }
 30         public MailUtil(int index)
 31         {
 32             this.Init(index, 5, "", "", "", "");
 33         }
 34         public MailUtil(int index, int type)
 35         {
 36             this.Init(index, type, "", "", "", "");
 37         }
 38         public MailUtil(int index, int type, string gender)
 39         {
 40             this.Init(index, type, gender, "", "", "");
 41         }
 42         public MailUtil(int index, int type, string gender, string online)
 43         {
 44             this.Init(index, type, gender, online, "", "");
 45         }
 46         public MailUtil(int index, int type, string gender, string online, string province)
 47         {
 48             this.Init(index, type, gender, online, province, "");
 49         }
 50         public MailUtil(int index, int type, string gender, string online, string province, string city)
 51         {
 52             this.Init(index, type, gender, online, province, city);
 53         }
 54         #endregion
 55         private void Init(int index, int type, string gender,string online, string province, string city)
 56         {
 57                 index = 1;
 58                 this.Index = index;
 59                 this.Type = type;
 60                 this.Gender = gender;
 61                 this.Online = online;
 62                 this.Province = province;
 63                 this.City = city;
 64                 this.HasNext = true;
 65                 this.Province = HttpUtility.UrlEncode(Encoding.GetEncoding("utf-8").GetBytes(this.Province));
 66                 this.City = HttpUtility.UrlEncode(Encoding.GetEncoding("utf-8").GetBytes(this.City));
 67            
 68         }
 69         private string VisitSite()
 70         {
 71             string url = "http://blog.163.com/findFriend.do";
 72             StringBuilder sb = new StringBuilder();
 73             sb.AppendFormat("{0}?index={1}&type={2}",url,this.Index,this.Type);
 74             if(this.Gender!="") sb.AppendFormat("&{0}",this.Gender);
 75             if(this.Province!="")sb.AppendFormat("&{0}",this.Province);
 76             if(this.City!="")sb.AppendFormat("&{0}",this.City);
 77             if(this.Online!="")sb.AppendFormat("&{0}",this.Online);
 78           
 79             string html = UUHttpHelper.GetHtml(sb.ToString(), "gbk");
 80             return html;
 81         }
 82         public Dictionary<string,LinkMan> Extract()
 83         {
 84             LinkMan linkman =null;
 85             
 86             Dictionary<string, LinkMan> linkmans = new Dictionary<string, LinkMan>();
 87             string html = VisitSite();
 88             this.HasNext = html.Contains("下一页") ;
 89             if (!this.HasNext) return linkmans;
 90             MatchCollection matches = new Regex(@"openurl\('(?'base64'[^']+)','profile'\)""\s*class=""nick""\>(?'nick'[^<>]*)\s*\</a\>", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace).Matches(html);
 91             foreach (Match match in matches)
 92             {
 93                 linkman = new LinkMan();
 94                 linkman.Base64String = match.Groups["base64"].Value;
 95                      string unicode=Encoding.GetEncoding("Gbk").GetString(Convert.FromBase64String(linkman.Base64String));
 96                 linkman.Email = unicode.Contains("@126")?(string.Format("{0}.com",unicode)):(string.Format("{0}@163.com",unicode));
 97                 linkman.Nick = match.Groups["nick"].Value;
 98                 linkmans.Add(linkman.Base64String, linkman);
 99             }
100             matches = new Regex(@"<a\s*[^>]*>(?'area'[^<]*)</a>\s*</div>\s*</div>\s*<div class=""nav"">\s*<a\s*href=""javascript:void\(0\);""\s*(οnclick=""gFindFriend.openurl\s*\('(?'base64'[^']+)','blog'\)"")*>", RegexOptions.IgnoreCase).Matches(html);
101             foreach (Match match in matches)
102             {
103                 linkmans[match.Groups["base64"].Value].Area = match.Groups["area"].Value;
104             }
105             this.Index++;
106             return linkmans;
107
108         }
109        
110     }
111     /// <summary>
112     /// 联系人信息
113     /// </summary>
114    public class LinkMan
115     {
116         /// <summary>
117         /// 昵称
118         /// </summary>
119         public string Nick { get; set; }
120         /// <summary>
121         /// 邮箱地址前缀的base64字符串
122         /// </summary>
123         public string Base64String { get; set; }
124         /// <summary>
125         /// 邮箱地址
126         /// </summary>
127         public string Email { get; set; }
128         /// <summary>
129         /// 性别
130         /// </summary>
131         public string Sex { get; set; }
132         /// <summary>
133         /// 地区
134         /// </summary>
135         public string Area { get; set; }
136         /// <summary>
137         /// 省份
138         /// </summary>
139         public string Province { get; set; }
140         /// <summary>
141         /// 城市
142         /// </summary>
143         public string City { get; set; }
144         /// <summary>
145         /// 年龄
146         /// </summary>
147         public int Age { get; set; }
148     }
149    public class TestClass
150    {
151        public static bool Paused = false;
152       static MailUtil mailUtil = new MailUtil();
153       static Dictionary<string, LinkMan> linkmans = new Dictionary<string, LinkMan>();
154        public static Dictionary<string, LinkMan> TestMethod(System.Windows.Forms.ListView listView)
155        {
156           
157            System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(delegate
158            {
159                while (mailUtil.HasNext)
160                {
161
162                    Dictionary<string, LinkMan> list = mailUtil.Extract();
163                    foreach (KeyValuePair<string, LinkMan> kvp in list)
164                    {
165                        if (!linkmans.ContainsKey(kvp.Key))
166                        {
167                            linkmans.Add(kvp.Key, kvp.Value);
168                            System.Windows.Forms.ListViewItem viewItem = listView.Items.Add(linkmans.Count.ToString());
169                            viewItem.SubItems.Add(kvp.Value.Nick);
170                            viewItem.SubItems.Add(kvp.Value.Email);
171                            viewItem.SubItems.Add(kvp.Value.Area);
172                        }
173                    }
174                    if (Paused)
175                        break;
176                }
177                if (linkmans.Count == 0) throw new Exception("没有找到任何数据");
178
179            }));
180            thread.Start();
181            return linkmans;
182        }
183    }
184   
185 }
 

 

这个类调用起来相当简单,直接new一个实例之后,调用Extract()就可以了。但是这样的话就只能获取所有结果的第一页了,后面还有很多的页面就无法抓去了,因此要将里面一个url地址的index参数加1,并且还要判断返回的html页里面是不是含有“下一页”,没有的话就不用继续再抓了

所以我在后面结尾处又加上了一个测试类,供大家直接调用,省去了很多麻烦。因为是静态类,所直接这样调用就可以了。
TestClass.TestMethod(listView1);//这个中间的listView1是你实际上添加到你代码中的控件名称,当然,//前提是这个控件已经添加好了相对应的colume

 

 

因此,必须在对多线程进行人为干预和控制,所以对上篇文章中提到的测试类和方法进行了改进,增加了一个开关逻辑变量Paused,判断这个变量以决定线程是否继续,当然您可能有比这更好的方法,我这里只是抛砖引玉罢了。
 
1public class TestClass
 2    {
 3        public static bool Paused = false;
 4       static MailUtil mailUtil = new MailUtil();
 5       static Dictionary<string, LinkMan> linkmans = new Dictionary<string, LinkMan>();
 6        public static Dictionary<string, LinkMan> TestMethod(System.Windows.Forms.ListView listView)
 7        {
 8           
9            System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(delegate
 10            {
 11                while (mailUtil.HasNext)
 12                {
 13
14                    Dictionary<string, LinkMan> list = mailUtil.Extract();
 15                    foreach (KeyValuePair<string, LinkMan> kvp in list)
 16                    {
 17                        if (!linkmans.ContainsKey(kvp.Key))
 18                        {
 19                            linkmans.Add(kvp.Key, kvp.Value);
 20                            System.Windows.Forms.ListViewItem viewItem = listView.Items.Add(linkmans.Count.ToString());
 21                            viewItem.SubItems.Add(kvp.Value.Nick);
 22                            viewItem.SubItems.Add(kvp.Value.Email);
 23                            viewItem.SubItems.Add(kvp.Value.Area);
 24                        }
 25                    }
 26                    if (Paused)
 27                        break;
 28                }
 29                if (linkmans.Count == 0) throw new Exception("没有找到任何数据");
 30
31            }));
 32            thread.Start();
 33            return linkmans;
 34        }
 35    }
 
 
 
接下来是改一下调用的方式,这里面的button是你添加点击的按钮。
 
 
 
1private void button1_Click(object sender, EventArgs e)
 2        {
 3             if (this.button1.Text == "开始提取")
 4            {
 5                this.button1.Text = "中断";
 6                TestClass.Paused = false;
 7                links = TestClass.TestMethod(listView1);
 8            }
 9            else
 10            {
 11                this.button1.Text = "开始提取";
 12                TestClass.Paused = true;
 13            }
14         
15           
16         }
 
 
保存数据通常我们用数据库,本地数据库有access,当然我们这里不用数据库用到xml技术就可以了。
 
xml的操作其实很简单,这里为了我们以后调用方便,我还是把xml进行了一个简单的封装处理。
 
 
1 using System;
   2 using System.Collections.Generic;
   3 using System.Text;
   4 using System.Xml;
   5 using System.Runtime.CompilerServices;
 
 10 namespace System
 11 {
 12     public class U_Xml
 13     {
 14         public string FileName { get; set; }
 15         public XmlDocument XmlDoc { get; set; }
 16         public XmlElement RootElement { get; set; }
 17         public U_Xml()
 18         {
 19         }
 20         public U_Xml(string fileName ,string rootElement)
 21         {
 22               this.FileName = fileName;
 23               this.XmlDoc = new XmlDocument();//创建xml文档
 24               XmlDeclaration xmlDeclaration = this.XmlDoc.CreateXmlDeclaration("1.0", "utf-8", null);
 25               this.XmlDoc.AppendChild(xmlDeclaration);//添加申明
 26               this.RootElement =this.XmlDoc.CreateElement(rootElement);//创建根元素
 27               this.XmlDoc.AppendChild(this.RootElement); //添加根元素
 28              
29         }
 30
31         public static XmlDocument LoadFromFile(string fileName)
 32         {
 33             XmlDocument xmlDoc = new XmlDocument();
 34             xmlDoc.Load(fileName);//加载已经存在的文件
 35             return xmlDoc;
 36         }
 37         public void Save(string fileName)
 38         {
 39             if (!string.IsNullOrEmpty(fileName))
 40                 this.FileName = fileName;
 41             if (this.XmlDoc == null) throw new Exception("没有创建xml文档,无法保存");
 42             this.XmlDoc.Save(this.FileName);
 43         }
 44         public void Save()
 45         {
 46             Save("");
 47         }
 48     }
 49     /// <summary>
 50     /// 这个类,用到扩展方法,用起来相当方便,有点像jquery的链式编程
 51     /// </summary>
 52     public static class Methods
 53     {
 54       
55         /// <summary>
 56         /// 添加节点
 57         /// </summary>
 58         /// <param name="arr">
 59         ///  第一个参数:xml实例化类
 60         ///  第二个参数:节点名字
61         /// <returns></returns>
 62         public static XmlNode AddNode(this XmlElement _xmlElement, params object[] arr)
 63         {
 64           
65             U_Xml u_Xml=(U_Xml)arr[0];
 66            XmlNode xmlNode =u_Xml.XmlDoc.CreateNode(XmlNodeType.Element,(string)arr[1],"");
 67             _xmlElement .AppendChild(xmlNode);//添加节点
 68           return   xmlNode;
 69           
70         }
 71         /// <summary>
 72         /// 添加节点
 73         /// </summary>
 74         /// <param name="arr">
 75         /// 第一个参数:xml实例化类\n
 76         /// 第二个参数:节点名字
 77         /// </param>
 78         /// <returns></returns>
 79         public static XmlNode AddNode(this XmlNode _xmlElement, params object[] arr)
 80         {
 81             U_Xml u_Xml = (U_Xml)arr[0];
 82             XmlNode xmlNode = u_Xml.XmlDoc.CreateNode(XmlNodeType.Element, (string)arr[1],"");
 83             _xmlElement.AppendChild(xmlNode);//添加节点
 84             return xmlNode;
 85         }
 86         /// <summary>
 87         /// 添加属性
 88         /// </summary>
 89         /// <param name="arr">
 90         /// 第一个参数:xml实例化类\n
 91         /// 第二个参数:属性名称\n
 92         /// 第三个参数:属性值
 93         /// </param>
 94         /// <returns></returns>
 95         public static XmlAttribute AddAttibute(this XmlElement _xmlElement, params object[] arr)
 96         {
 97             U_Xml u_Xml = (U_Xml)arr[0];
 98            XmlAttribute xmlAttribute = u_Xml.XmlDoc.CreateAttribute((string)(arr[1]));
 99            xmlAttribute.Value = (string)arr[2];
 100            _xmlElement.Attributes.Append(xmlAttribute);
 101            return xmlAttribute;
 102         }
 103         /// <summary>
 104         /// 添加属性
 105         /// </summary>
 106         /// <param name="arr">
 107         /// 第一个参数:xml实例化类\n
 108         /// 第二个参数:属性名称\n
 109         /// 第三个参数:属性值
 110         /// </param>
 111         /// <returns></returns>
 112         public static XmlAttribute AddAttibute(this XmlNode _xmlElement, params object[] arr)
 113         {
 114             U_Xml u_Xml = (U_Xml)arr[0];
 115             XmlAttribute xmlAttribute = u_Xml.XmlDoc.CreateAttribute((string)(arr[1]));
 116             xmlAttribute.Value = (string)arr[2];
 117             _xmlElement.Attributes.Append(xmlAttribute);
 118             return xmlAttribute;
 119         }
120          public static XmlNode ReName(this XmlElement _xmlElement, params object[] arr)
 121         {
 122             string value = (string)arr[2];
 123          
124             U_Xml u_Xml=(U_Xml)arr[0];
 125             XmlNode xmlElement = u_Xml.XmlDoc.CreateNode("element",value,"");
 126             if (u_Xml.XmlDoc[(string)arr[1]] == null) throw new Exception("不存在该节点");
 127                xmlElement.InnerText = u_Xml.XmlDoc[(string)arr[1]].InnerText;
 128             u_Xml.XmlDoc[(string)arr[1]].ParentNode.ReplaceChild(xmlElement,u_Xml.XmlDoc[(string)arr[1]]);
 129             u_Xml.Save();
 130             return xmlElement;
 131         }
 132         public static XmlNode ReName(this XmlNode _xmlElement, params object[] arr)
 133         {
 134             string value = (string)arr[2];
 135
136             U_Xml u_Xml = (U_Xml)arr[0];
 137             XmlNode xmlElement = u_Xml.XmlDoc.CreateNode("element", value, "");
 138             xmlElement.InnerText = u_Xml.XmlDoc[(string)arr[1]].InnerText;
 139             u_Xml.XmlDoc[(string)arr[1]].ParentNode.ReplaceChild(xmlElement, u_Xml.XmlDoc[(string)arr[1]]);
 140             u_Xml.Save();
 141             return xmlElement;
 142         }
 143         public static void Delete(this XmlNode _xmlElement)
 144         {
 145             if (_xmlElement == null) throw new Exception("该节点不存在");
 146            if(_xmlElement.ParentNode.HasChildNodes) _xmlElement.ParentNode.RemoveChild(_xmlElement);
 147         }
 148     }
 149
150 }
 
 
1   private void button2_Click(object sender, EventArgs e)
 2         {
 3             U_Xml u_Xml = new U_Xml(Environment.CurrentDirectory + "\\Config\\MailInfo.xml", "MailSet");
 4             foreach (KeyValuePair<string, LinkMan> kvp in links)
 5             {
 6                XmlNode xmlNode= u_Xml.RootElement.AddNode(u_Xml, "Email");
 7                xmlNode.AddAttibute(u_Xml, "Nick", kvp.Value.Nick);
 8                xmlNode.AddAttibute(u_Xml, "Area", kvp.Value.Area);
 9                xmlNode.InnerText = kvp.Value.Email;
 10             }
 11             u_Xml.Save();
 12            
13         }
 
 
 

首先,我们还是先介绍一下通过程序发送邮件的几种方式。
 
1.Smtp方式.
 
这种方式比较傻瓜化,在C#里调用起来也相对简单(其他语言像java也有类似的Pocket(包)可以直接调用,相当简单)。通常在.net里,存在两个线程的类可以使用:
 
一个是System.Net.Mail,另一个就是Sytem.Web.Mail,当然还有没有其他类我也没去细究过了。然而后面那个类现在VS里已经提示说过时了,那就用前面的那个类吧。
 
调用方法如下,先添加对System.Net.Mail的引用。代码如下:
 
1 /// <summary>
 4    /// </summary>
 5     public class MailSender
 6    {
 7        public SmtpClient Client { get; set; }
 8        public MailMessage Msg { get; set; }
 9        private string[] To { get; set; }
 10        private string SmtpServer { get; set; }
 11        private int Port { get; set; }
 12        public MailSender()
 13        {
 14           
15        }
 16
17        public MailSender(string from, string smtpServer, string username, string password)
 18        {
 19            this.Init(from, smtpServer,username,password);
 20        }
 21        private void Init(string from, string smtpServer,string username,string password)
 22        {
 23            this.Msg = new MailMessage();
 24            this.Client = new SmtpClient(smtpServer);
 25            this.SmtpServer = smtpServer;//发送邮箱的Smtp服务器地址
 26            this.Client.UseDefaultCredentials = true;
 27            this.Client.Credentials = new NetworkCredential(username, password);//这里是必须填写的邮箱登录用户名和密码
 28            this.Msg.From = new MailAddress(from);//设置邮件发送地址
 29            this.Msg.IsBodyHtml = true;//这里最好设置为html格式的邮件正文
 30             this.Msg.BodyEncoding = Encoding.UTF8;//邮件正文编码
 31            this.Msg.SubjectEncoding = Encoding.UTF8;
 32            this.Msg.DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure;//当邮件发送失败的时候通知一下
 33           
34        }
 35        public void Send(string subject,string body,string[] attachmentPaths)
 36        {
 37
38           
39            for (int i = 0; i < attachmentPaths.Length; i++)
 40            {
 41                this.Msg.Attachments.Add(new Attachment(attachmentPaths[i]));
 42            }
 43            this.Msg.Subject = subject;
 44            this.Msg.Body = body;
 45             this.Client.Send(this.Msg);
 46            
47        }
 48    }
 
这个发送邮件的封装类没有起到封装的作用,还等待各位去补充完善,代码很简单,调用的话,请接着看下面的代码
 
 
 
 
 
2         /// copyright:No
 5         /// </summary>
 6         /// <param name="sender"></param>
 7         /// <param name="e"></param>
 8         private void button3_Click(object sender, EventArgs e)
 9         {
 10            try
 11              {
 12                 MailSender mailSender = new MailSender("wxp146@qq.com", "smtp.qq.com", "wxp146", "******");//Rember that it's your password
 13                 links = new Dictionary<string, LinkMan>();
 14                 for (int i = 0; i < listView1.CheckedItems.Count; i++)
 15                 {
 16                     ListViewItem listViewItem = listView1.Items[listView1.CheckedItems[i].Index];
 17                     LinkMan linkMan = new LinkMan();
 18                     string id = listViewItem.Text;
 19                     string nick = listViewItem.SubItems[1].Text;
 20                     string email = listViewItem.SubItems[2].Text;
 21                     string area = listViewItem.SubItems[3].Text;
 22                     linkMan.Nick = nick;
 23                     linkMan.Email = email;
 24                     linkMan.Area = area;
 25                     mailSender.Msg.To.Add(linkMan.Email);
 26
27
28                     links.Add(linkMan.Email, linkMan);
 29
30                 }
 31               
32                 /*
 33                  * mailSender.Msg.Subject = "这是一封测试信,可以直接放垃圾箱!";
 34                 mailSender.Msg.Body = "你好:测定试一下,打扰之处请见谅!<a href=\"HTTP://www.uu102.com\">曙光营销技术论坛</a>";
 35                 mailSender.Client.Send(mailSender.Msg);
 36                  *
 37                  */
 38                 mailSender.Send("这是一封测试信,可以直接放垃圾箱!",
 39                                  "你好:测定试一下,打扰之处请见谅!<a href=\"HTTP://www.uu102.com\">曙光营销技术论坛</a>",
 40                                  new string[] { Environment.CurrentDirectory + "\\Config\\MailInfo.xml" });
 41                 MessageBox.Show("邮件发送成功");
 42              }
 43             catch (WebException e1)
 44             {
 45                 MessageBox.Show(string.Format("邮件发送失败,请检查设置{0}",e1.Message));
 46             }
47         }
 
 
 
至于上面的代码突然出现的button3是一个点击发送的按钮。以上就是我们要介绍的第一种邮件发送方式
 
2.模拟登陆邮箱管理页面,然后模拟发送。
 
典型的做法有登录QQ邮箱然后发帖的,网上很多人都在研究这种方式。当然,由于时间和精力的关系,我就没直接贴出代码了,有兴趣的朋友可以联系本人,一起交流探讨一下。
 
3.利用IIS的Smtp邮箱服务发送
 
这种方法大概是最麻烦的了,要求在自己的机器上装这装那,还不一定会成功。当然,如果你有个人的网站服务器的话,这个也不失为一个办法。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值