• 使用vb.net编写一个邮件定时发送程序(三)


        一不小心,国庆长假就结束了,上班第一天抓紧时间把其余的部分放上来吧。

        首先进行数据库的结构设计,在我的设想中,最少应该有三个数据表,一个是发件箱(mail_outbox),用来存放准备发送的邮件,一个是已发送(mail_sent),发送正确的邮件都被写入这个表中,还有一个是发送错误(mail_error),发送时出现问题的邮件就存放在这里,就这个小程序而言,它最主要的功能是将mail_outbox中的邮件发送出去,具体数据是怎么被写入这个数据表的,我们就先不讨论了。

        大体的思路确定以后,就可以开始进行设计了,数据表的字段应该包括发件人姓名、收件人地址、收件人姓名、主题、内容、是否HTML邮件、拟发送时间、邮件优先级等内容,本来还想再加入一个回复邮件地址的项目,后来发现不知道为什么,Jmail4.4中都还有的ReplyTo属性,在Jmail.Net 1.1中竟然没有了,也就不再加这个字段了。建表语句如下:

    CREATE TABLE [dbo].[mail_outbox](
    	[mail_id] [int] IDENTITY(1,1) NOT NULL,
    	[mail_sendtime] [datetime] NULL,
    	[mail_sendname] [nvarchar](30) NULL,
    	[mail_toemail] [varchar](50) NULL,
    	[mail_toname] [nvarchar](30) NULL,
    	[mail_subject] [nvarchar](100) NULL,
    	[mail_body] [nvarchar](max) NULL,
    	[mail_html] [bit] NULL,
    	[mail_Priority] [char](1) NULL,
    	[mail_flag] [char](1) NULL,
    	[mail_senduser] [varchar](14) NULL,
     CONSTRAINT [PK_mail_outbox] PRIMARY KEY CLUSTERED 
    (
    	[mail_id] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    

        在对该表进行读取时,最多的动作就是检查是否已经到了预定的发送时间,因此在这个表上对mail_sendtime增加了一条索引,加快处理速度。

    create index idx_mailoutbox on mail_outbox
    (mail_sendtime)
    

        Mail_sent表、Mail_error表与Mail_outbox表的结构基本相同,只是增加了一个Mail_senttime字段记录实际的发送时间及Mail_error字段记录报错信息,同时去掉了Mail_id的主键及自动增长,并没有加上任何索引。

    代码
    1 create table mail_sent
    2 (
    3 mail_id int,
    4 mail_sendtime datetime,
    5 mail_sendname nvarchar(30),
    6 mail_toemail varchar(50),
    7 mail_toname nvarchar(30),
    8 mail_subject nvarchar(100),
    9 mail_body nvarchar(max),
    10 mail_html bit,
    11 mail_Priority char(1),
    12 mail_flag char(1),
    13 mail_senduser varchar(14),
    14 mail_senttime datetime
    15 );
    16  create table mail_error
    17 (
    18 mail_id int,
    19 mail_sendtime datetime,
    20 mail_sendname nvarchar(30),
    21 mail_toemail varchar(50),
    22 mail_toname nvarchar(30),
    23 mail_subject nvarchar(100),
    24 mail_body nvarchar(max),
    25 mail_html bit,
    26 mail_Priority char(1),
    27 mail_flag char(1),
    28 mail_senduser varchar(14),
    29 mail_senttime datetime,
    30 mail_error_msg varchar(200)
    31 )
    32

        数据表建好后,开始增加程序功能,因为数据库使用的是微软自己的SQL SERVER 2005,因此就使用了SqlClient.SqlConnection来进行连接,新建一个名为sql_conn.vb的类,将主要功能都进入,然后在主程序中进行调用。

    Public Class sql_conn
        Private Shared Conn As SqlClient.SqlConnection
        Public Shared connStr As String
        Public Shared Function Open() As Boolean '连接数据库
            Try
                Conn = New SqlClient.SqlConnection(connStr)
                Conn.Open()
                Return True
            Catch
                'MsgBox("数据库无法连接1", MsgBoxStyle.OkOnly, "错误")
                Return False
            End Try
        End Function
    
    
        Public Shared Function Open(ByVal p_ServerName As String, ByVal p_UID As String, ByVal p_PassWord As String, ByVal p_DataBase As String) As Boolean '连接数据库,四个参数是服务器名,用户名,密码,数据库名
            Try
                connStr = "server=" + p_ServerName + ";User ID =" + p_UID + ";password=" + p_PassWord + ";database =" + p_DataBase
                Conn = New SqlClient.SqlConnection(connStr)
                Conn.Open()
                Return True
            Catch
                'MsgBox("数据库无法连接2", MsgBoxStyle.OkOnly, "错误")
                Return False
            End Try
        End Function
    
    #Region "得到数据集"
        Public Shared Function GetDS(ByVal strSql As String) As DataSet '通过Sql语句得到数据集
            If Conn Is Nothing Then
                Open()
            End If
            Dim DS As New DataSet
            Dim sqlComm As New SqlClient.SqlCommand(strSql, Conn)
            Dim sqlDA As New SqlClient.SqlDataAdapter(sqlComm)
            Try
                sqlDA.Fill(DS)
                sqlComm.Cancel()
                Return DS
            Catch
                MsgBox(Err.Description, MsgBoxStyle.OkOnly, "错误")
                Return Nothing
            End Try
        End Function
    #End Region
    
    #Region "执行Sql语句"
        Public Shared Function Exec_Sql(ByVal strSql As String) As Integer  '执行Sql语句,不返回数据集
            If Conn Is Nothing Then
                Open()
            End If
            Dim sqlComm As New SqlClient.SqlCommand(strSql, Conn)
            Dim SqlCount As Integer = 0
            Try
                SqlCount = sqlComm.ExecuteNonQuery() '执行Sql语句
                sqlComm.Cancel()
                Return SqlCount
            Catch
                'MsgBox(Err.Description, "错误")
                Return -1
            End Try
        End Function
    #End Region
    End Class
    
    
    

        在一般常见的代码中,对于exec_sql这类不需要返回数据集的sql执行语句一般都选择了返回Boolean值,但我选择了返回一个Integer值,最主要的功能是用来返回update数据库时受影响的记录条数,方便下一步的判断和继续操作。

        好,现在数据库的结构和连接、读写数据库的代码都有了,要实现循环读取待发邮件的功能,我们还需要再加上一个Timer控件,将控件拖到Form中,在用户点击“开始”按钮执行程序时对Timer进行处理,我设定的Interval值为1000,也就是第一秒运行一次,这样的话就可以把扫描的间隔时间按秒数进行设定,十分方便,而且也比较精确。

        下面是“开始”按钮及Timer_Tick的代码:

        Private Sub Btn_Start_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Btn_Start.Click
            If Running = False Then
                If Txt_ScanSec.Text < 30 Or Txt_ScanSec.Text > 86400 Then
                    MessageBox.Show("扫描的间隔时间不应小于30秒或大于86400秒,请重新设置!", "注意", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                    Txt_ScanSec.Text = "180"
                    Exit Sub
                End If
                If Not Open(Txt_DbServer.Text, Txt_DbUser.Text, DbPassword, Txt_DataBase.Text) Then
                    MessageBox.Show("数据库连接有误,请检查后再运行程序程序!", "注意", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                    Exit Sub
                End If
                Running = True
                RunStrat = Now()
                Btn_Start.Text = "停止(&S)"
                Btn_Exit.Enabled = False
                Btn_SaveIni.Enabled = False
                'Tbl_Main.Enabled = False
                Txt_ScanSec.ReadOnly = True
                Chk_LogFile.Enabled = False
                Tbl_Main.TabPages(1).Enabled = False
                Tbl_Main.TabPages(2).Enabled = False
                'ReadRow("select * from yn_login where user_role = '2'")
                Time_SendMail.Interval = 1000
                Time_SendMail.Enabled = True
                Time_SendMail.Start()
                Txt_Message.Text = RunStrat + "程序开始运行……" + vbCrLf
    
            Else
                Time_SendMail.Stop()
                Time_SendMail.Enabled = False
                Running = False
                Btn_Start.Text = "开始(&S)"
                Btn_Exit.Enabled = True
                Btn_SaveIni.Enabled = True
                Txt_ScanSec.ReadOnly = False
                Chk_LogFile.Enabled = True
                Tbl_Main.TabPages(1).Enabled = True
                Tbl_Main.TabPages(2).Enabled = True
            End If
        End Sub
    
        Private Sub Time_SendMail_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Time_SendMail.Tick
            If ScanSec >= Txt_ScanSec.Text Then
                Time_SendMail.Stop()
                Txt_Message.Text = "正在进行邮件发送……" + vbCrLf + "启动时间:" + Now()
                SentOutBox()
                Application.DoEvents()
                ScanCount = ScanCount + 1
                Txt_Message.Text = "本次扫描启动于" + RunStrat + vbCrLf + "共扫描了" + ScanCount.ToString + "次,发送成功邮件" + SendSuc.ToString + "封,失败" + SendErr.ToString + "封!" + vbCrLf + "暂停" + Txt_ScanSec.Text.ToString + "秒,等待下一次扫描……" + vbCrLf
                ScanSec = 0
                Time_SendMail.Start()
            Else
                ScanSec = ScanSec + 1
                Txt_Message.Text = Txt_Message.Text + "."
            End If
        End Sub
    
    

        这样的话,整个程序的主要步骤就已经完成了,剩下来的就是一些小细节方面的改动,将在下一节的时候再和大家一一交流。

    作者:vvian

    出处:http://www.cnblogs.com/vvian/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,非常感谢。

  • 相关阅读:
    html文件引用本地js文件出现跨域问题的解决方案
    【移动端】cordova 更改app的图标、名字、加载画面以及强制横竖屏
    thinkphp5.0返回插入数据id
    ThinkPHP5 隐藏index.php问题
    密码强度正则表达式 – 必须包含大写字母,小写字母和数字,至少8个字符等
    php实现微信分享朋友圈
    HTML Input 表单校验之datatype
    TP5:使用了INPUT函数来接收参数了,还需再过滤SQL注入吗
    大商创微信公众号微信支付失败报错
    $GLOBALS — 引用全局作用域中可用的全部变量
  • 原文地址:https://www.cnblogs.com/vvian/p/1845543.html
Copyright © 2020-2023  润新知