【通知】
【通知】充值首选支付宝,未及时到账,请邮件联系 youjianqunfa@qq.com 备注用户名。
当前位置:首页 > 邮箱群发百科 > 正文内容
7月5日

时间:2020-07-05 13:00

一个简易邮件群发软件设计与实现

0
分类:邮箱群发百科 | 评论:0人 | 浏览:73次   

1 需求概述

指定一批邮箱地址,使用指定的邮箱发送指定的内容。

2 功能需求

  • 配置文件配置用于发送的邮箱信息
  • 邮件发送功能
  • 日志窗口输出显示

3 界面接口

  • 邮件列表框
  • 标题内容输入框
  • 发送按钮
  • 日志输出框

4 技术选型

.Net 4.0 C# Winform

5 实现

5.1 新建项目

  • 项目命名为 SimpleEmailSender
    一个简易邮件群发软件设计与实现

5.2 在项目中添加配置文件

一个简易邮件群发软件设计与实现

  • 配置发件邮箱信息
<configuration>   <appSettings>     <add key="email_stmp" value="smtp.****.com"/>     <add key="send_user_email" value="****@****"/>     <add key="send_user_pass" value="密码"/>     <add key="send_user_disp" value="发件人昵称" />   </appSettings> </configuration> 

5.3 制作界面

根据界面接口需求,界面布局如下:
一个简易邮件群发软件设计与实现

5.4 邮件发送辅助类

首先完成辅助类开发,最后再跟界面对接完成流程。
因为读取了配置文件,需要添加 System.Configuration 程序集的引用。
一个简易邮件群发软件设计与实现

定义 MailHelper 辅助类,读取配置参数,向外提供发送邮件功能方法 SendMail。

using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Net.Mail; using System.Text;  namespace SimpleEmailSender {     public class MailHelper     {         public static String EMAIL_USERNAME = ConfigurationManager.AppSettings["send_user_email"];         public static String EMAIL_DISPNAME = ConfigurationManager.AppSettings["send_user_disp"];         public static String EMAIL_PASSWORD = ConfigurationManager.AppSettings["send_user_pass"];         public static String EMAIL_SMTP = ConfigurationManager.AppSettings["email_stmp"];         public static ValidateResult SendMail(string email, string name, string content)         {             return SendMail("系统消息", email, name, content);         }          /// <summary>         /// 发送邮件         /// </summary>         /// <param name="title">邮件标题</param>         /// <param name="email">收件人地址</param>         /// <param name="name">收件人名称</param>         /// <param name="content">邮件内容</param>         public static ValidateResult SendMail(string title, string email, string name, string content)         {             MailAddress from = new MailAddress(EMAIL_USERNAME, EMAIL_DISPNAME); //邮件的发件人             MailMessage mail = new MailMessage();             //设置邮件的标题             mail.Subject = title;              //设置邮件的发件人             //Pass:如果不想显示自己的邮箱地址,这里可以填符合mail格式的任意名称,真正发mail的用户不在这里设定,这个仅仅只做显示用             mail.From = from;              //设置邮件的收件人             mail.To.Add(new MailAddress(email, name));              //设置邮件的内容             mail.Body = content;              //设置邮件的格式             mail.BodyEncoding = System.Text.Encoding.UTF8;             mail.IsBodyHtml = true;             //设置邮件的发送级别             mail.Priority = MailPriority.Normal;              mail.DeliveryNotificationOptions = DeliveryNotificationOptions.OnSuccess;              SmtpClient client = new SmtpClient();             //设置用于 SMTP 事务的主机的名称,填IP地址也可以了             client.Host = EMAIL_SMTP;              //设置用于 SMTP 事务的端口,默认的是 25             client.Port = 25;             client.UseDefaultCredentials = false;             //这里才是真正的邮箱登陆名和密码             client.Credentials = new System.Net.NetworkCredential(EMAIL_USERNAME, EMAIL_PASSWORD);             client.DeliveryMethod = SmtpDeliveryMethod.Network;             //都定义完了,正式发送了,很是简单吧!               ValidateResult vr = new ValidateResult(true, "发送成功!");             try             {                 client.Send(mail);                 return vr;             }             catch (Exception e)             {                 vr.IsValid = false;                 vr.Message = e.Message;                 return vr;             }         }     }      public class ValidateResult     {         public bool IsValid { get; set; }         public string Message { get; set; }          public ValidateResult() {           }          public ValidateResult(bool v, string m)         {             IsValid = v;             Message = m;         }     } }  

5.5 清单解析

对于邮箱列表,使用正则表达式从文本框中匹配邮箱形成 List emailList 给后续执行。这样,对邮箱列表文本框中输入的格式就没什么要求,从其它地方复制粘贴进来,由程序完成格式化显示即可。

        /// <summary>         /// 提取邮件列表         /// </summary>         /// <param name="mails"></param>         /// <returns></returns>         private List<string> ParseEmailList(string mails)         {             List<string> list = new List<string>();             var mc = Regex.Matches(mails, @"w+([.-]?w+)*@w+([.-]?w+)*(.w{2,3})+", RegexOptions.IgnoreCase);              foreach (Match c in mc)             {                 list.Add(c.Value);             }             return list;         } 

5.6 日志输出方法准备

在日志框中输出内容,为了能在线程中调用,使用了 Invoke 方式执行。

/// <summary> /// 日志输出支持线程中执行 /// </summary> /// <param name="message"></param> private void Log(string message) {     Invoke(new MethodInvoker(delegate     {         txtLog.AppendText(message + "rn");     })); } 

5.7 线程发送

  • 发送方案设计

基本描述:给定邮箱列表,标题与内容,以线程方式执行发送,给出执行统计与状态。
具体实现:使用线程池,但一组做为一个任务,全部完成才接收下一个任务,通过完成数量与邮箱列表长度的比较来判断是否全部完成,信息通过日志输出的方式查看,形式上通过回调将日志信息传递给调用者。

为此,这里专门定义一个发送器,在应用中,定义一个实例来发起任务。尽管只定义一个实例,但这里并不需要定义为设计模式中的单例模式,事实上,它是可以多实例运行。具体代码说话!

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading;  namespace SimpleEmailSender {     public class EmailSender     {         #region 运行时数据         // 邮箱列表         private List<string> _EmailList = new List<string>();         // 完成数量         private volatile int _OverCount = 0;         // 邮件标题         private string _Title;         // 邮件内容         private string _Content;         // 完成回调(主要是为了写日志)         private Action<string> _Callback;         #endregion          /// <summary>         /// 是否全部完成         /// </summary>         /// <returns></returns>         public bool IsOver()         {             return _OverCount == _EmailList.Count;         }          /// <summary>         /// 发起任务(如果不符合发起条件,则返回 false)         /// </summary>         /// <param name="emails"></param>         /// <param name="title"></param>         /// <param name="content"></param>         /// <param name="callback"></param>         /// <returns></returns>         public bool Send(List<string> emails, string title, string content, Action<string> callback)         {             if (!IsOver())             {                 return false;             }              _EmailList = emails;             _OverCount = 0;             _Title = title;             _Content = content;             _Callback = callback;              Start();             return true;         }          /// <summary>         /// 启动任务         ///          /// 以线程池方式运行,每个邮箱不论成败完成数加1,并回调通知。         /// </summary>         private void Start()         {             foreach (string email in _EmailList)             {                 var _email = email;                 ThreadPool.QueueUserWorkItem(t =>                 {                     var vr = MailHelper.SendMail(_Title, _email, "", _Content);                     _OverCount++;                     _Callback(String.Format("进度[{3}/{4}] {0} 发送 {1},返回:{2}", _email, vr.IsValid ? "成功" : "失败", vr.Message, _OverCount, _EmailList.Count));                 });             }         }       } }  

5.8 按钮事件

发送按钮执行的流程为:如果之前的任务尚未完成,则等待。否则,首先提取邮箱列表,并格式化显示,然后发起任务,观察日志即可。

        private EmailSender _Sender = new EmailSender();           // 发送按钮         private void btnSend_Click(object sender, EventArgs e)         {             if (!_Sender.IsOver())             {                 Log("之前的任务尚未完成,请等待完成!");                 return;             }              // 1. 提取邮件列表并格式化显示             string mails = txtEmailList.Text.Trim();             var list = ParseEmailList(mails);             // 2. 格式化显示一下             txtEmailList.Clear();             foreach (var mail in list)             {                 txtEmailList.AppendText(mail + "rn");             }             // 3. 发起任务             var b = _Sender.Send(list, txtTitle.Text.Trim(), txtContent.Text, Log);             Log(b ? "发起成功" : "发起失败");         } 

6 运行结果

6.1 配置信息错误时

一个简易邮件群发软件设计与实现

6.2 配置信息正确时

一个简易邮件群发软件设计与实现

7 项目源代码

https://github.com/triplestudio/SimpleEmailSender

欢迎访问

  • 评论:(0)
  • 有图有真相

已有 0 位网友发表了一针见血的评论,你还等什么?

你必须 登录 才可以留言.