Introduction
SuperMail.NET is a bulk emailing application written in VB.NET using System.Net.Mail, MS Access, and My.Settings. It is still not completely finished, but it has come a long way from the time I first posted this article. Even though it's not finished, I have decided to do the update anyway because I think there are some good samples here for anyone interested in System.Net.Mail. I use this app at work all the time for the HTML newsletters I send out to clients. You can download the source code above and use SuperMail.NET as well; however, I would recommend running it in an IDE as I have not yet added all the exception handling.
What SuperMail.NET does is allow you to store your newsletters or HTML emails on your web server in the form of .htm files, and then scrape the HTML replacing any specified text (the recipient name, date, etc..), and then send them out to a list you import into an Access database using field mapping.
Before we look at the code, here are a couple of bullets listing what this article covers, for quick reference:
- Using the
System.Net.Mail namespace to send email with Visual Basic .NET 2005
- How to scrape HTML from a web page using
System.Net.WebRequest in Visual Basic .NET 2005
- How to save user settings in the app.config file using
My.Settings in Visual Basic .NET 2005
- Looping through a
DataGridView in Visual Basic .NET 2005
Using the Code
This is the sub routine I am using to create and send the emails. Notice that I am scraping the HTML, replacing the recipient name, and then inserting it into the body of the email. Also, I reference My.Settings for the settings that were entered by the user for everything else (sending email account, port number, subject line, credentials, etc.). The If statements are looking to see if the user specified to use credentials or SSL.
Private Sub SendEmail( ByVal emailAddress As String, _
ByVal name As String)
Me.Cursor = Cursors.WaitCursor
Dim strMailBody As String = ScreenScrapeHtml(CStr(cbSelectEmail.Text))
strMailBody = strMailBody.Replace("SoNso", name)
Dim mail As New System.Net.Mail.MailMessage()
mail.From = New System.Net.Mail.MailAddress(my.Settings.EmailAccount)
mail.To.Add(emailAddress)
mail.IsBodyHtml = True
mail.Subject = CStr(cbEmailSubject.Text)
mail.Body = strMailBody
Dim smtp As New System.Net.Mail.SmtpClient(CStr(My.Settings.SMPT))
smtp.Port = My.Settings.Port
If My.Settings.UseAuthentication = True Then
smtp.Credentials = New System.Net.NetworkCredential( _
My.Settings.UserName, My.Settings.Password)
End If
If My.Settings.SSL = True Then
smtp.EnableSsl = True
End If
smtp.Send(mail)
Me.Cursor = Cursors.Arrow
End Sub
This is the function I use to scrape the HTML from the server and put it into a variable:
Public Function ScreenScrapeHtml( ByVal url As String) As String
Dim objRequest As System.Net.WebRequest = _
System.Net.HttpWebRequest.Create(url)
Dim sr As New IO.StreamReader(objRequest.GetResponse().GetResponseStream())
Dim result As String = sr.ReadToEnd()
sr.Close()
Return result
End Function
This is the code I use to send an individual email, or loop through the DataGrigView and send out the entire list. I think my current technique for looping through the items works fine for now, but I am looking to change it so it will identify the column headers to grab the correct fields. This way, once I have it worked out, you can import lists directly from the application. It won't mater how many columns are in the DataGridView as long as the headers are named correctly. I am still trying to decide the best way to do it. This does, however, show one way to do it, and can be modified to fit individual needs.
Private Sub btnSend_Click( ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnSend.Click
If ckbSend1.Checked = True Then
Dim strEmail As String = txtToAddress.Text
Dim strName As String = txtRecName.Text
SendEmail(strEmail, strName)
End If
If ckbSendAll.Checked = True Then
Dim strName As String
Dim strEmail As String
Dim i As Integer = 0
For Each row As DataGridViewRow In DataGridView1.Rows
strName = CStr(DataGridView1.Item(1, i).Value)
strEmail = CStr(DataGridView1.Item(2, i).Value)
If strName = "" Then
Exit For
End If
SendEmail(strEmail, strName)
i += 1
Next
End If
MessageBox.Show("Your message(s) have beed sent!")
End Sub
This class is for a tool I created to save user settings to My.Settings. It is accessible from the menu strip, and is one of three I have built so far. There is also one for saving URLs for up to five different HTML emails, and one for saving subject lines. I only put up the code for this one because they all pretty much work the same way. You would need to first right click on the project properties and add the settings. You would want to use user settings as they are readable and writable, whereas application settings are read only. It's a pretty straightforward process, and I found it to be extremely useful in this case. You don't even have to edit the XML in app.config; Visual Studio does everything for you. Once you add the settings in the project properties, you can immediately read from them, and write to them, as shown below:
Imports System.Windows.Forms
Public Class UserSettings
Private Sub OK_Button_Click( ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles OK_Button.Click
My.Settings.EmailAccount = txtUserEmail.Text
My.Settings.SMPT = txtSMTP.Text
If ckbUseAuthentication.Checked = False Then
My.Settings.UseAuthentication = False
txtUserName.Enabled = False
txtPassword.Enabled = False
End If
If ckbUseAuthentication.Checked = True Then
My.Settings.UseAuthentication = True
My.Settings.UserName = txtUserName.Text
My.Settings.Password = txtPassword.Text
End If
If ckbSSL.Checked = True Then
My.Settings.SSL = True
Else
My.Settings.SSL = False
End If
My.Settings.Port = CInt(txtPortNumber.Text)
Me.Refresh()
MessageBox.Show("Saved")
End Sub
Private Sub Cancel_Button_Click( ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Cancel_Button.Click
Me.DialogResult = System.Windows.Forms.DialogResult.Cancel
Me.Close()
End Sub
Private Sub UserSettings_Load( ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
txtUserEmail.Text = My.Settings.EmailAccount
txtSMTP.Text = My.Settings.SMPT
If My.Settings.UseAuthentication = False Then
ckbUseAuthentication.Checked = False
txtUserName.Enabled = False
txtPassword.Enabled = False
End If
If My.Settings.UseAuthentication = True Then
ckbUseAuthentication.Checked = True
txtUserName.Text = My.Settings.UserName
txtPassword.Text = My.Settings.Password
End If
If My.Settings.SSL = True Then
ckbSSL.Checked = True
Else
ckbSSL.Checked = False
End If
txtPortNumber.Text = My.Settings.Port
End Sub
Private Sub ckbUseAuthentication_CheckedChanged( ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles ckbUseAuthentication.CheckedChanged
If ckbUseAuthentication.Checked = True Then
txtUserName.Enabled = True
txtPassword.Enabled = True
End If
If ckbUseAuthentication.Checked = False Then
txtUserName.Enabled = False
txtPassword.Enabled = False
End If
End Sub
End Class