VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > VB.net教程 >
  • 使用vb.net编写一个邮件定时发送程序(三)

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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增加了一条索引,加快处理速度。

1
2
create index idx_mailoutbox on mail_outbox
(mail_sendtime)

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

 

代码

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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

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

 

 



相关教程