lrary

时光荏苒,岁月流逝,仅以此纪念那一段走过来的开发岁月,希望哪天回首时,仍能想起一幕幕难忘的日子。

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::
例如有一个注册的用户蒋涛,电子地址为anony@anonymous.com,订阅了关于“大米”的商业信息,那么蒋涛的电子邮箱就会定期收到类似于下面的电子邮件:
[code]
尊敬的蒋涛:
以下是您订阅的高速路信息速递:

求购荞麦大米黄豆绿豆
我公司求购大量荞麦大米黄豆绿豆等酿酒原料
公司名称:江西某某某商贸有限公司
联系人:某某某
电话:000-55556666
电子邮件:mmm@mmm.com


现金求购大米
我公司现款长期求购大米
公司名称:西安某某国际贸易公司
联系人:某某
电话:029-66669898
电子邮件:xianmoumou@xian.com
 
... ...

更多信息,请访问高速路

[/code]
开始的时候,觉得还是满复杂的,任务涉及SMTP配置、信息搜索,邮件生成等诸多子任务。尤其是通过程序调用SMTP服务器发送邮件,以前根本没有接触过,基本无从下手。
但感觉上.net Framework可能封装了相应的类,于是调出MSDN开始查找,结果被我发现了System.Net.Mail namespace,事情好像也没有我原来预想的那么复杂。
于是开启Visual C#开始尝试,初期的想法是在服务器上用asp.net做一个搜索的页面,可以接收一个字符串变量,在服务器端完成搜索,那么只要通过Visual C#发送一个类似于下面的邮件便可:
[code]
<HTML>
<HEAD>
<meta http-equiv="refresh" content="0;url=http://www.gaosulu.com/search.aspx?keyword=大米">
</HEAD>
<BODY>
</BODY>
</HTML>
[/code]
客户收到电子邮件的时候就会自动跳转到搜索结果页面,由服务器完成数据库搜索,将结果以HTML的格式返回客户端。
用outlook写了一个类似上面的邮件,发送到另一个邮箱,接受的时候却发现有些问题:如果客户是通过web页面浏览邮件,可顺利完成页面跳转,担如果客户是通过outlook软件将邮件收取到本地,则不能完成页面跳转。我想这大概是微软出于安全方面的因素,屏蔽了这个功能。看来只能写一个“邮件生成器”,把完整的信息以HTML的形式发送给客户。
另外,C#的程序也出现了一些问题。SmtpClient类有一个Credentials属性,用于存储SMTP服务器的身份认证信息,鉴于现在大多数SMTP服务器都需要判断发送者的身份,Credentials属性是必须设定的。但是MSDN上的sample中Credentials设定的是CredentialCache.DefaultNetworkCredentials。网上google到的sample大多也比较含糊。
又看了看MSDN,Credentials属性只接受实现了ICredentialsByHost接口的类实例,而ICredentialsByHost有一个GetCredential 方法返回一个NetworkCredential类型的实例,经过查询,NetworkCredential实现了ICredentials, ICredentialsByHost接口。也就是说,只需创建一个NetworkCredential类的实例,将其赋予SmtpClient的Credentials属性,就可以完成SMTP的身份认证。NetworkCredential类的构造函数如下:
[code]
public NetworkCredential (
 string userName,
 string password
)
[/code]
邮件发送程序还需要声明一个MailMessage类用于存储电子邮件,MailMessage构造函数如下:
[code]
public MailMessage (
 string from,
 string to,
 string subject,
 string body
)
[/code]
完整的邮件发送类的代码如下:
[code]
/*****************************************/
/* Project name: MailDaemon              */
/* Module name: Mail Sender              */
/* Author: Ming Yeh                      */
/* Created date: 2006-08-21              */
/* Last modified by:                     */
/* Last modify date:                     */
/*                .-._                   */
/*               {_}^ )o                 */
/*      {\________//~`                   */
/*       (         )                     */
/*       /||~~~~~||\                     */
/*      |_\\_    \\_\_                   */
/*                                       */
/*****************************************/
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Mail;
using System.Text;

namespace mailDaemon
{
    class MailSender
    {
        private const string SERVER_IP = "61.181.255.80";
        private const string SENDER_EMAIL = "mailist@gaosulu.com";
        private const string USERNAME = "xxxxxxxx";
        private const string PASSWORD = "xxxxxxxx";
        private const string SUBJECT = "高速路商机速递";
        string _server;
        string _senderEmail;
        string _username;
        string _password;

        public MailSender(string server, string senderEmail, string username, string password)
        {
            _server = server;
            _senderEmail = senderEmail;
            _username = username;
            _password = password;
        }
        public MailSender():this(SERVER_IP, SENDER_EMAIL, USERNAME, PASSWORD)
        {
           
        }
        public void SendMail(string email, string content)
        {
            MailMessage msg = new MailMessage(_senderEmail, email, SUBJECT, content);
            msg.BodyEncoding = Encoding.UTF8;
            msg.Priority = MailPriority.High;
            msg.IsBodyHtml = true;
            SmtpClient client = new SmtpClient(_server);
            NetworkCredential credential = new NetworkCredential(_username, _password);
            client.UseDefaultCredentials = false;
            client.Credentials = credential;
            client.SendCompleted += new SendCompletedEventHandler(client_SendCompleted);
            client.SendAsync(msg, "Message Sent.");
            Console.WriteLine(email + "邮件发送中...");
            Console.WriteLine(email + "处理完成");
        }

        void client_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            String token = (string)e.UserState;

            if (e.Cancelled)
            {
                Console.WriteLine("[{0}] Send canceled.", token);
            }
            if (e.Error != null)
            {
                Console.WriteLine("[{0}] {1}", token, e.Error.ToString());
            }
            else
            {
                Console.WriteLine("Message sent.");
            }
            mailSent = true;
        }
    }
}
[/code]
这里我使用了SmtpClient的SendAsync方法,以免阻塞进程。
还有一个类用于生成邮件,这里的字符串处理使用了StringBuilder,以获得更好的性能。
[code]
/*****************************************/
/* Project name: MailDaemon              */
/* Module name: MailContentGenerator     */
/* Author: Ming Yeh                      */
/* Created date: 2006-08-21              */
/* Last modified by:                     */
/* Last modify date:                     */
/*                .-._                   */
/*               {_}^ )o                 */
/*      {\________//~`                   */
/*       (         )                     */
/*       /||~~~~~||\                     */
/*      |_\\_    \\_\_                   */
/*                                       */
/*****************************************/
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Text;

namespace mailDaemon
{
    class MailGenerator
    {
        private const int RECORD_COUNT = 10;
        string _contact;
        string _keyword;
        StringBuilder _mailContent;
        public MailGenerator(string contact,string keyword)
        {
            _contact = contact;
            _keyword = keyword;
            _mailContent = new StringBuilder();
            GenerateMailContent();
        }
        //hide the default constructor
        private MailGenerator()
        {
        }
        public string MailContent
        {
            get
            {
                return _mailContent.ToString();
            }
        }
        public int Length
        {
            get
            {
                return _mailContent.Length;
            }
        }
        private void GenerateMailContent()
        {
            _mailContent.AppendLine("<HTML>");
            //the HEAD section
            _mailContent.AppendLine("<HEAD>");
            _mailContent.AppendLine("<TITLE>高速路商机速递</TITLE>");
            _mailContent.AppendLine("<META NAME=\"Generator\" CONTENT=\"EditPlus\">");
            _mailContent.AppendLine("<META NAME=\"Author\" CONTENT=\"Ming Yeh\">");
            _mailContent.AppendLine("<META NAME=\"Keywords\" CONTENT=\"gaosulu\">");
            _mailContent.AppendLine("<META NAME=\"Description\" CONTENT=\"gaosulu maillist email\">");
            _mailContent.AppendLine("</HEAD>");
            //the BODY section
            _mailContent.AppendLine("<BODY>");
            _mailContent.AppendLine("尊敬的" + _contact + ":<br>");
            _mailContent.AppendLine("以下是您订阅的高速路信息速递:");
            if (GetInfo().Rows.Count == 0)
            {
                //Sigh,there is no data
                _mailContent.AppendLine("<p><b>暂时没有您订阅的信息</b></p>");
            }
            else
            {
                foreach (DataRow dr in GetInfo().Rows)
                {
                    _mailContent.AppendLine("<p>");
                    _mailContent.AppendLine("<b><a href=\"http://www.gaosulu.com/sca_view.asp?id=" + dr["smt_id"].ToString() + "\" target=\"_blank\">" + dr["smt_scatitle"].ToString() + "</b></a><br>");
                    _mailContent.AppendLine(dr["smt_sca"].ToString() + "<br>");
                    _mailContent.AppendLine("公司名称:" + dr["SMT_com"].ToString() + "<br>");
                    _mailContent.AppendLine("联系人:" + dr["SMT_name"].ToString() + "<br>");
                    _mailContent.AppendLine("电话:" + dr["SMT_tel"].ToString() + "<br>");
                    _mailContent.AppendLine("电子邮件:" + dr["SMT_email"].ToString() + "<br>");
                    _mailContent.AppendLine("</p>");
                }
            }
            _mailContent.AppendLine("<p><a href=\"http://www.gaosulu.com\" target=\"_blank\">更多信息,请访问高速路</a></p>");
            _mailContent.AppendLine("</BODY>");
            _mailContent.AppendLine("</HTML>");
        }
        private DataTable GetInfo()
        {
            DataSet ds = new DataSet();
            SqlDataAdapter sda = new SqlDataAdapter("select top " + RECORD_COUNT.ToString() + " * from smt_sca where smt_scatitle like '%" + _keyword + "%' order by smt_begindate desc", SingleConnection.GetConnection());
            sda.Fill(ds, "InfoData");
            return ds.Tables[0];
        }
    }
}
[/code]
数据库连接类套用了Singleton模式
[code]
/*****************************************/
/* Project name: MailDaemon              */
/* Module name: Single Connection        */
/* Author: Ming Yeh                      */
/* Created date: 2006-08-21              */
/* Last modified by:                     */
/* Last modify date:                     */
/*                .-._                   */
/*               {_}^ )o                 */
/*      {\________//~`                   */
/*       (         )                     */
/*       /||~~~~~||\                     */
/*      |_\\_    \\_\_                   */
/*                                       */
/*****************************************/
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Text;

namespace mailDaemon
{
    class SingleConnection
    {
        private const string CONNECT_STRING = "Data Source=61.181.255.80;Initial Catalog=scadata;Persist Security Info=True;User ID=XXXX;password=XXXX;Connection Timeout=1000";
        static SqlConnection _conn;
        private SingleConnection()
        {
            //private constructor
        }
        public static SqlConnection GetConnection()
        {
            if (_conn == null)
            {
                _conn = new SqlConnection(CONNECT_STRING);
            }
            //if (_conn.State != ConnectionState.Open)
            //{
            //    _conn.Open();
            //}
            return _conn;
        }
    }
}
[/code]
还有一个类,用于从数据库中搜索生成邮件所需的信息
[code]
/*****************************************/
/* Project name: MailDaemon              */
/* Module name: Mail List Data           */
/* Author: Ming Yeh                      */
/* Created date: 2006-08-21              */
/* Last modified by:                     */
/* Last modify date:                     */
/*                .-._                   */
/*               {_}^ )o                 */
/*      {\________//~`                   */
/*       (         )                     */
/*       /||~~~~~||\                     */
/*      |_\\_    \\_\_                   */
/*                                       */
/*****************************************/
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Text;

namespace mailDaemon
{
    class MailListData
    {
        private const string SELECT_COMMAND = "select * from smt_mail";
        public static string USER_EMAIL = "smt_user_mail";
        public static string MAIL_KEYWORD = "smt_keyword";
        public static string CONTACT_PERSON = "smt_contact_person";
        private DataSet _ds = new DataSet();
        public MailListData(string sql)
        {
            SqlDataAdapter sda = new SqlDataAdapter(sql, SingleConnection.GetConnection());
            sda.Fill(_ds, "MailList");
        }
        public MailListData():this(SELECT_COMMAND)
        {
        }
        public DataTable MailData
        {
            get
            {
                return _ds.Tables[0];
            }
        }
        public int count
        {
            get
            {
                return _ds.Tables.Count;
            }
        }
    }
}
[/code]
主程序的代码很少^_^
[code]
/*****************************************/
/* Project name: MailDaemon              */
/* Module name: Main Program             */
/* Author: Ming Yeh                      */
/* Created date: 2006-08-21              */
/* Last modified by:                     */
/* Last modify date:                     */
/*                .-._                   */
/*               {_}^ )o                 */
/*      {\________//~`                   */
/*       (         )                     */
/*       /||~~~~~||\                     */
/*      |_\\_    \\_\_                   */
/*                                       */
/*****************************************/
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;

namespace mailDaemon
{
    class Program
    {
        static void Main(string[] args)
        {
            MailListData mld = new MailListData();
            foreach (DataRow dr in mld.MailData.Rows)
            {
                MailGenerator mg = new MailGenerator(dr[MailListData.CONTACT_PERSON].ToString(), dr[MailListData.MAIL_KEYWORD].ToString());
                MailSender ms = new MailSender();
                ms.SendMail(dr[MailListData.USER_EMAIL].ToString(), mg.MailContent);
            }
            Console.WriteLine("所有任务处理完成");
        }
    }
}
[/code]
只要build这个程序,在windows中设置为计划任务,就可以了。
当然,还有一些需要改进的地方:
1、邮件的格式比较单一,如果采用模版的形式可以更加灵活一些,也许可以通过调用CodeSmith实现?
2、邮件的发送部分如果采用多线程,效率可能会更好一些。
3、用户的管理方面可以更加灵活一些,这些细节是release前需要大量人工的地方。 

原文:http://blog.csdn.net/chieftech/archive/2006/08/22/1105914.aspx

posted on 2006-08-23 14:50  lrary  阅读(540)  评论(0)    收藏  举报