zoukankan      html  css  js  c++  java
  • C# 使用windows服务发送邮件

    最近做了一个使用 C# 写了一个发送邮件的 windows 服务,在这里记录一下。

    首先使用 Visual Studio 2015 创建一个 windows 服务项目。

    然后在设计器上面右击添加安装程序。如下图。

    安装好后,选择安装程序设计界面,选择服务和安装程序右击选择属性修改一些属性值。

    PS:如果不给服务添加安装程序,后面是没法把服务安装至 windows 系统里的。

    在数据库创建一个表,用于存储需要发送的邮件信息。

    create table MainInfo
    (
        MainInfoID    int  not null identity(1,1) primary key,
        Mail_To  nvarchar(64) not null,    -- 收件人邮箱
        Title nvarchar(128) not null,    -- 邮件标题
        Content nvarchar(max)  null, -- 邮件内容
        Mode int not null default(0), -- 发送方式,0为默认发送,1为抄送,2为密送
        SendState int not null default(0), -- 发送状态,0为未发送,1为发送成功,2为发送失败
        IsTimer int not null default(0), -- 0为即时发送,1为定时发送
        SendTime nvarchar(64) null,        -- 定时发送的时间
        AttAchFileUrl nvarchar(max) null,    -- 添加附件的地址
        AttAchFileName nvarchar(128) null,  -- 附件名称
        IsServerUrl int null default(0)    -- 附件地址是否为服务器地址
    )

    下面开始贴出代码:

    SqlHelper.cs,访问数据库类。

    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Data;
    using System.Data.SqlClient;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace SendMail
    {
        public class Conn
        {
            public static string StrConn
            {
                get
                {
                    //读取文本文件(txt)
                    //return Conn.getValue(@"C:UsersBramblingDesktopDemoSendMailSendMailDB_ConfigDB_Config.txt", "StrConn");
    
                    //读取配置文件
                    //return ConfigurationManager.ConnectionStrings["StrConn"].ToString();
                    //return ConfigurationManager.AppSettings["Conn"].ToString();
                    
                    //直接返回数据库连接字符串
                    return "Data Source=.;Initial Catalog=Test;User ID=sa;Pwd=xxxxxx;Enlist=true;Pooling=true;Max Pool Size=300;Min Pool Size=0;Connection Lifetime=300;packet size=1000";
                }
            }
    
            public static SqlConnection SqlConn
            {
                get
                {
                    return new SqlConnection(StrConn);
                }
            }
    
            private static string getValue(string path, string name)
            {
                string[] str = File.ReadAllLines(path);
                for (int i = 0; i < str.Length; i++)
                {
                    if (str[i].StartsWith(name))
                    {
                        return str[i].Replace(name + "=", "");
                    }
                }
                return "";
            }
        }
    
    
        public class SqlHelper
        {
            public DataSet GetDataSet(string sql)
            {
                DataSet ds = new DataSet();
                SqlConnection conn = Conn.SqlConn;
                try
                {
                    conn.Open();
                    SqlDataAdapter sda = new SqlDataAdapter(sql, conn);
                    sda.Fill(ds);
                }
                catch (Exception)
                {
                }
                finally
                {
                    conn.Close();
                }
                return ds;
            }
    
            public DataTable GetDataTable(string sql)
            {
                DataSet ds = new DataSet();
                DataTable dt = new DataTable();
                SqlConnection conn = Conn.SqlConn;
                try
                {
                    conn.Open();
                    SqlDataAdapter sda = new SqlDataAdapter(sql, conn);
                    sda.Fill(ds);
                    if (ds != null && ds.Tables.Count > 0)
                    {
                        dt = ds.Tables[0];
                    }
                }
                catch (Exception)
                {
                }
                finally
                {
                    conn.Close();
                }
                return dt;
            }
    
            public bool ExecSql(string sql)
            {
                int num = 0;
                SqlConnection conn = Conn.SqlConn;
                try
                {
                    conn.Open();
                    SqlCommand cmd = new SqlCommand(sql, conn);
                    num = cmd.ExecuteNonQuery();
                }
                catch (Exception)
                {
                }
                finally
                {
                    conn.Close();
                }
                return num > 0;
            }
        }
    }
    SqlHelper

    这里我尝试了读取配置文件的数据库连接串,但是好像 windows 服务读取不到配置文件。还有个办法就是读取一个文本文件(txt)。

    文本文件(txt)的连接串写法:

    StrConn=Data Source=.;Initial Catalog=Test;User ID=sa;Pwd=xxxxxx;Enlist=true;
    Pooling=true;Max Pool Size=300;Min Pool Size=0;Connection Lifetime=300;packet size=1000

    Mail.cs,发送邮件类。

    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.Mail;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace SendMail
    {
        public class Mail
        {
            SqlHelper sqlhelper = new SqlHelper();
    
            public void SendMail()
            {
                MailMessage mailmsg = null;
                NetworkCredential credential = null;
                SmtpClient client = null;
    
                string sql = " select top 1 * from MainInfo where SendState='0' and (IsTimer='0' or (IsTimer='1' and SendTime is not null and Convert(datetime,SendTime)<=getdate())) order by IsTimer,SendTime ";
                DataTable dt = sqlhelper.GetDataTable(sql);
                if (dt != null && dt.Rows.Count > 0)
                {
                    string Id = dt.Rows[0]["MainInfoID"].ToString();
    
                    try
                    {
                        //创建一个身份凭证,即发送邮件的用户名和密码
                        credential = new NetworkCredential("980095349@qq.com", "xxxxxx");
    
                        //发送邮件的实例,服务器和端口
                        client = new SmtpClient("smtp.qq.com", 25);
                        //发送邮件的方式,通过网络发送
                        client.DeliveryMethod = SmtpDeliveryMethod.Network;
                        //是否启用 SSL 
                        client.EnableSsl = true;
                        //指定发送邮件的身份凭证
                        client.Credentials = credential;
    
                        //发送的邮件信息
                        mailmsg = new MailMessage();
    
                        // 指定发件人邮箱和显示的发件人名称
                        mailmsg.From = new MailAddress("980095349@qq.com", "午夜游魂");
    
                        // 指定收件人邮箱
                        MailAddress mailto = new MailAddress(dt.Rows[0]["Mail_To"].ToString());
                        if (dt.Rows[0]["Mode"].ToString() == "1")
                        {
                            mailmsg.CC.Add(mailto);     // 抄送
                        }
                        else if (dt.Rows[0]["Mode"].ToString() == "2")
                        {
                            mailmsg.Bcc.Add(mailto);    // 密送
                        }
                        else
                        {
                            mailmsg.To.Add(mailto);     // 默认发送
                        }
    
                        //邮件主题
                        mailmsg.Subject = dt.Rows[0]["Title"].ToString();
                        mailmsg.SubjectEncoding = Encoding.UTF8;
    
                        //邮件内容
                        mailmsg.Body = dt.Rows[0]["Content"].ToString();
                        mailmsg.BodyEncoding = Encoding.UTF8;
    
                        //添加附件
                        string url = dt.Rows[0]["AttAchFileUrl"].ToString();    // 附件地址
                        string name = dt.Rows[0]["AttAchFileName"].ToString();   // 附件名称
                        if (dt.Rows[0]["IsServerUrl"].ToString() == "1")    // 判断附件地址是否为服务器地址
                        {
                            if (!string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(name))
                            {
                                // 从指定的服务器附件地址加载附件,并转换为 IO 流 添加到邮件附件中
                                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                                Stream stream = response.GetResponseStream();
    
                                mailmsg.Attachments.Add(new Attachment(stream, name));
                            }
                        }
                        else
                        {
                            if (!string.IsNullOrEmpty(url))
                            {
                                mailmsg.Attachments.Add(new Attachment(@url));   // 本地路径可直接加载
                            }
                        }
    
                        client.Send(mailmsg);   // 发送邮件
                        UpdateState(Id, "1");   // 发送成功修改发送状态为 1
                    }
                    catch (Exception ex)
                    {
                        UpdateState(Id, "2");   // 发送失败修改发送状态为 2
                    }
                }
            }
    
            public bool UpdateState(string Id, string state)
            {
                string SendTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
    
                string sql = " update MainInfo set SendState='" + state + "',SendTime='" + SendTime + "' where MainInfoID='" + Id + "' ";
                bool b = sqlhelper.ExecSql(sql);
                return b;
            }
        }
    }
    Mail

    在这里我把发送邮件的用户、密码、服务器、端口等都是写死的。实际使用中可以考虑单独建立一张发送邮件的配置表,和邮件信息表关联起来。

    SendMailMain.cs,设置定时器类。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Timers;
    
    namespace SendMail
    {
        public class SendMailMain
        {
            // 设置定时器
            private System.Timers.Timer t = null;
    
    
            public void Init()
            {
                try
                {
                    if (t == null)
                    {
                        t = new System.Timers.Timer();
                        t.Elapsed += new ElapsedEventHandler(SendMail);     // 绑定事件
                        t.Interval = 5000;      // 指定执行的间隔时间
                        t.Enabled = true;   // 是否启用执行 System.Timers.Timer.Elapsed 事件
                        t.AutoReset = true;     // 设置为 true 表示一直执行,false 为只执行一次
                    }
                }
                catch
                {
                    t.Stop();
                    t.Dispose();
                }
            }
    
            private void SendMail(object sender, ElapsedEventArgs args)
            {
                try
                {
                    ((System.Timers.Timer)sender).Enabled = false;  //单线程管控
                    Mail mail = new Mail();
                    mail.SendMail();
                }
                catch (Exception)
                {
                    throw;
                }
                finally
                {
                    ((System.Timers.Timer)sender).Enabled = true;  //单线程管控
                }
            }
        }
    }
    SendMailMain

    Service1.cs,服务开始类。

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    using System.Linq;
    using System.ServiceProcess;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace SendMail
    {
        public partial class Service1 : ServiceBase
        {
            public Service1()
            {
                InitializeComponent();
    
                // 启用 暂停和恢复服务功能
                //base.CanPauseAndContinue = true;
            }
    
            // 服务开始执行方法
            protected override void OnStart(string[] args)
            {
                SendMailMain sm = new SendMailMain();
                sm.Init();
            }
    
            // 服务停止执行方法
            protected override void OnStop()
            {
            }
    
            // 计算机关闭执行方法
            protected override void OnShutdown()
            {
            }
    
            // 恢复服务执行方法
            protected override void OnContinue()
            {
            }
    
            // 暂停服务执行方法
            protected override void OnPause()
            {
            }
    
        }
    }
    Service1

    上面就是完全的代码了,下面先创建一个测试单元,测试一下发送邮件。

    首先在数据库插入一条要发送的邮件信息的数据:

    insert into MainInfo(Mail_To,Title,Content,AttAchFileUrl,AttAchFileName,IsServerUrl)
      values('1171588826@qq.com','测试邮件','测试邮件,请勿回复!',
      'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1494357502809&di=66d6a7909bfe54624a16e02caefb9838&imgtype=0&src=http%3A%2F%2F5.66825.com%2Fdownload%2Fpic%2F000%2F330%2F7599586ba2ba3bed5d76ea182883fca6.jpg',
      '孙悟空.jpg','1')

    然后直接使用测试单元调用发送邮件的方法:

    using System;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using SendMail;
    using System.IO;
    
    namespace UnitTest
    {
        [TestClass]
        public class UnitTest1
        {
            [TestMethod]
            public void TestMethod1()
            {
                Mail mail = new Mail();
                mail.SendMail();
            }
        }
    }

    发送成功了。

    下面开始安装 windows 服务。

    首先找到路径 C:WindowsMicrosoft.NETFrameworkv4.0.30319 或者路径 C:WindowsMicrosoft.NETFrameworkv2.0.50727 下面的 InstallUtil.exe,具体是哪一个下面的,根据版本而定。

    然后新建一个文件夹,把刚刚找到的 InstallUtil.exe 文件和 bin Debug 或者 Release 文件夹下编译好的文件全部复制到该文件夹下。

    然后以管理员身份运行 cmd,输入如下图命令安装 windows 服务。

    使用 InstallUtil.exe SendMail.exe /u 命令卸载安装的服务。

    或者使用下面这种简单的方法。

    附上代码:

    @echo 启动安装服务中....
    @Set installPath=C:WindowsMicrosoft.NETFrameworkv4.0.30319InstallUtil.exe
    @Set serversName=SendMailService
    @goto checkFile
    :checkFile
        @echo 检测Framework安装路径: %installPath%
        @IF NOT EXIST "%installPath%" GOTO filed 
        @IF EXIST "%installPath%" GOTO success
    :run
        @rem 
        @set /p type=请选择服务操作模式,安装(1),卸载(2),退出(3)...
        @IF "%type%"==""  goto run
        @IF "%type%"=="1" goto runInstall
        @IF "%type%"=="2" goto runUnInstall
        @IF "%type%"=="3" exit
    :success
        @echo 地址检测完成
        @rem 
        @goto run
    :filed
        @echo 检测失败,当前路径文件不存在...
        @set /p installPath=请重新指定物理路径:
        @goto checkFile
    :runInstall
        %installPath% SendMail.exe
        @rem
        @net start %serversName%
        @pause
        
        @goto run
    :runUnInstall
        @rem
        @net stop %serversName%
        @sc delete %serversName%
        @pause
        @rem
        @goto run
    代码

    把上面这一段代码复制到新建的文本文件(txt)中,然后把后缀改为 bat,然后把它和 bin Debug 或者 Release 文件夹下编译好的文件放到同一个文件夹下。然后执行这个后缀为 bat 的文件,根据提示的步骤就可以很简单的安装和卸载服务了。

    启动服务命令: net start SendMailService(服务的名称)

    停止服务命令: net stop SendMailService(服务的名称)

    PS:如果安装的服务的文件进行了修改,但是路径没有变化的话是不需要重新注册服务的,直接停止服务,然后用新的文件覆盖原来的文件即可,如果路径发生变化,应该先卸载这个服务,然后重新安装这个服务。

    最后一步,因为这个服务依赖于 sql server ,所以需要把服务设置为延迟启动。

    选中服务右击,选择属性。把启动类型设置为:自动(延迟启动)。

    这样一个使用 windows 服务发送邮件的功能就完成了。现在可以把服务开启,然后向数据库插入一条邮件信息的数据,试试看效果。

  • 相关阅读:
    ibatis resultMap 结果集映射
    iabtis初探
    struts2获取请求参数的三种方式及传递给JSP参数的方式
    Struts2的运行机制简介
    Spring AOP面向切面编程的实现
    java 单例模式及getInstance的好处
    It is indirectly referenced from required .class files
    AngularJS学习篇(二)
    AngularJS学习篇(一)
    Flex布局语法
  • 原文地址:https://www.cnblogs.com/Brambling/p/6828726.html
Copyright © 2011-2022 走看看