Sending Email

A recurring need for many Web sites is to generate and send email messages. A commercial site, for instance, normally sends order confirmations to customers who purchase products or services. Sites with memberships routinely correspond with members to keep them up to date on site policies and features. In other cases, automated email feedback is provided when inquiries are made. There are numerous occasions in which Web pages need to handle routine email correspondence to relieve individuals from having to manually produce email themselves.

ASP.NET pages can be configured to send email through the server's SMTP (Simple Mail Transfer Protocol) service. This is, as the name implies, a limited email service; however, it is sufficient for generating and sending automated emails from Web pages. The SMTP service is included as a component of Microsoft Windows Server and XP Professional. It may have to be installed and initiated if it were not part of a default installation.

If your are running ASP.NET under XP Professional on your desktop computer (localhost), you may need to configure it to permit relay of email messages. Perform the following steps:

  1. Open IIS Administrative Tools.
  2. Stop Default SMTP Virtual Server service.
  3. Open properties window of Default SMTP Virtual Server.
  4. Click "Access" tab and click "Relay..." button.
  5. Click "Only the list below" button and add the single computer at IP address 127.0.0.1.
  6. Click "OK" buttons to close "Access" tabs and properties window.
  7. Restart Default SMTP Virtual Server service.

Web pages that produce automated email messages must import the System.Net.Mail namespace. This namespace contains classes used to send electronic mail to an SMTP server for delivery.

<%@ Import Namespace="System.Net.Mail" %>
Listing 10-43. Importing the System.Net.Mail namespace to produce email messages.

Three classes are included in the namespace. The MailMessage class represents the content of a mail message. The SmtpClient class transmits email to the SMTP host server designated for mail delivery. Email attachments are sent using the Attachment class.

The SmtpClient Class

All email messages are sent through an SmtpClient object. The general format for creating this object is given in Figure 10-36.

Dim EmailClient As SmtpClient
EmailClient = New SmtpClient(host)

or

Dim EmailClient = New SmtpClient(host)
Figure 10-36. General format to create an SmtpClient object.

The host is a string identifying the host server through which SMTP services are provided for sending email. In most cases, these services reside on the same server that hosts the Web page producing the message. Therefore, the string is typically "localhost".

The SmtpClient object supplies the Send() method through which email messages are sent through the host server. The easiest and most direct way to produce and send an email message is through four string parameters that can be coded in the Send() method.

EmailClient.Send(from, to, subject, body)
Figure 10-37. General format to create an SmtpClient object.

In this format, from is the "From" address, to is the "To" address, subject is the "Subject" line, and body is the "Body" of the message. All four parameters must be present and must appear in the order given.

The following example script is run on a button click to compose and send an email through the SmtpClient. Here, the four Send() parameters are declared and valued as hard-coded strings.

<%@ Import Namespace="System.Net.Mail" %>

<SCRIPT Runat="Server">

Sub Send_Email (Src As Object, Args As EventArgs)

  Dim MailFrom As String = "dadams@mail.maconstate.edu"
  Dim MailTo As String = "dadams@mail.maconstate.edu"
  Dim MailSubject As String = "Subject Line."
  Dim MailBody As String = "This is the message."
  
  Dim MailClient = New SmtpClient("localhost")
  MailClient.Send(MailFrom, MailTo, MailSubject, MailBody)

End Sub

</SCRIPT>

<form Runat="Server">

<asp:Button Text="Send Email" OnClick="Send_Email" Runat="Server"/>

</form>
Listing 10-44. Composing and sending a simple email.

This technique makes it fairly easy to compose and send an email with the four items collected from a form. You can use the following example to send an email to yourself.

Send Email

To:
From:
Subject:
Message:


Figure 10-38. Sending an email through a form.
<%@ Import Namespace="System.Net.Mail" %>

<SCRIPT Runat="Server">

Sub Send_Email (Src As Object, Args As EventArgs)
  
  If MailFrom.Text <> "" _
    AND MailTo.Text <> "" _
    AND Subject.Text <> "" _
    AND Body.Text <> "" Then
      Try
        Dim MailClient = New SmtpClient("localhost")
        MailClient.Send(MailFrom.Text, MailTo.Text, Subject.Text, Body.Text)
        MailMsg.Text = "Email sent"
      Catch
        MailMsg.Text = "Error in sending email!"
      End Try
  End If
	
End Sub

</SCRIPT>

<form Runat="Server">

<h3>Send Email</h3>

<table border="1" style="border-collapse:collapse">
<tr>
  <td style="font-weight:bold; background-color:#E0E0E0">To:</td>
  <td><asp:TextBox id="MailTo" Width="200" Runat="Server"/></td>
</tr>
<tr>
  <td style="font-weight:bold; background-color:#E0E0E0">From:</td>
  <td><asp:TextBox id="MailFrom" Width="200" Runat="Server"/></td>
</tr>
<tr>
  <td style="font-weight:bold; background-color:#E0E0E0">Subject:</td>
  <td><asp:TextBox id="Subject" Width="300" Runat="Server"/></td>
</tr>
<tr>
  <td style="font-weight:bold; background-color:#E0E0E0">Message:</td>
  <td><asp:TextBox id="Body" Runat="Server"
        TextMode="MultiLine" Rows="5" Width="300"
        Font-Name="Arial"/></td>
</tr>
</table>
<br/>
<asp:Button Text="Send Email" OnClick="Send_Email" Runat="Server"/>
<asp:Label id="MailMsg" ForeColor="#FF0000" Runat="Server"/>

</form>
Listing 10-45. Sending an email through a form.

The MailMessage Class

A more formal way of composing messages sent through an SmtpClient, and one that provides more flexibility to define message components, is through a MailMessage object. This object defines the sender, recipients, subject, and message body required by the SmtpClient, which then sends the final MailMessage. A MailMessage object is created using the formats shown in Figure 10-39.

Dim MailMessage As MailMessage
MailMessage = New MailMessage

or

Dim MailMessage = New MailMessage
Figure 10-39. General format to create an MailMessage object.

Once a MailMessage object is created and its sender, recipients, subject, body, and other properties are set, the message is sent through the SmtpClient.

Dim SmtpClient = New SmtpClient("localhost")
Dim MailMessage = New MailMessage

...set MailMessage sender, recipients, subject, and body properties

SmtpClient.Send(MailMessage)
Listing 10-46. Sending a MailMessage through an SmtpClient.

Properties that can be defined for a MailMessage include From (sender address), ReplyTo (alternate sender address), To (recipients' addresses), CC (carbon-copy recipients' addresses), Bcc (blind carbon-copy recipients' addresses), Subject (subject line), Body (body of the message), and Attachments (attachments to the message).

Creating Email Addresses

Email addresses associated with a MailMessage must be declared as MailAddress objects. These objects are populated with sender and recipient email addresses and then assigned to the MailMessage as From and To properties. Different techniques are used to assign these two properties.

The From Property

A MailMessage's From property is set by creating a MailAddress object, assigning an address string to the object, and then assigning this object to the MailMessage's From property. The formats shown in Figure 10-40 can be used.

Dim FromAddress As MailAddress
FromAddress = New MailAddress(address)
MailMessage.From = FromAddress

or

Dim FromAddress = New MailAddress(address)
MailMessage.From = FromAddress

or

MailMessage.From = New MailAddress(address)
Figure 10-40. General formats to create a MailAddress for assignment to a MailMessage's From property.

The following example should help clarify. Here, a MailMessage (MyEmail) is created for sending an email through an SmtpClient (MyClient). A new MailAddress (FromAddress) is created for the sender of the message, supplying an email address string. This address is assigned as the MailMessage's From property prior to sending the email.

Dim MyEmail = New MailMessage
Dim MyClient = New SmtpClient("localhost")

Dim FromAddress = New MailAddress("dadams@mail.maconstate.edu")
MyEmail.From = FromAddress
...

MyClient.Send(MyEmail)
Listing 10-47. Code to create a MailAddress for assignment to a MailMessage's From property.

This same technique is used to set the optional ReplyTo property of the message. The ReplyTo property supplies an email address other than the From address to use to reply to the message.

The To Property

A MailMessage's To property is set by creating a MailAddress object, assigning an address string to the object, and then adding (not assigning) this object to the MailMessage's To property. Creating a To address uses the same formats as for assignment to the From property; the difference is in how the address is associated with the MailMessage.

Dim ToAddress As MailAddress
ToAddress = New MailAddress(address)
MailMessage.To.Add(ToAddress)

or

Dim ToAddress = New MailAddress(address)
MailMessage.To.Add(ToAddress)

or

MailMessage.To.Add(New MailAddress(address))
Figure 10-41. General formats to create a MailAddress to add to a MailMessage's To collection.

A MailMessage's To property is a collection of email addresses to which is added a newly declared address through its Add() method. Again, an example should help clarifiy by continuation of the previous script.

Dim MyEmail = New MailMessage
Dim MyClient = New SmtpClient("localhost")

Dim FromAddress = New MailAddress("dadams@mail.maconstate.edu")
MyEmail.From = FromAddress

Dim ToAddress = New MailAddress("myfriend@hotmail.com")
MyEmail.To.Add(ToAddress)
...

MyClient.Send(MyEmail)
Listing 10-48. Code to create a MailAddress to add to a MailMessage's To collection.

As you can see, any number of recipients can be designated by creating a MailAddress for each and adding the address to the MailMessage's To collection. It may be likely that a list of email recipients is stored in a database. In this case, you can retrieve the email field and create multiple MailAddresses that are added to a MailMessage. A skeletal script to perform this processing is shown below.

Dim MyEmail = New MailMessage
Dim MyClient = New SmtpClient("localhost")

Dim FromAddress = New MailAddress("dadams@mail.maconstate.edu")
MyEmail.From = FromAddress

'-- Create MailAddresses from a database
Create Connection object and open database 
Create Command object and issue SQL command
Create DataReader object
While DataReader.Read()

  Dim ToAddress = New MailAddress(DataReader("EmailField"))
  MyEmail.To.Add(ToAddress)

End While
Close DataReader
Close Connection
...

MyClient.Send(MyEmail)
Listing 10-49. Code to create multiple MailAddresses from a database.

The CC and Bcc Properties

Similar methods are used to declare one or more carbon-copy (CC property) and blind carbon-copy (Bcc property) recipients of a MailMessage. That is, these properties, like the To property, have Add() methods to include lists of recipients.

Dim MyEmail = New MailMessage
Dim MyClient = New SmtpClient("localhost")

Dim FromAddress = New MailAddress("dadams@mail.maconstate.edu")
MyEmail.From = FromAddress

Dim ToAddress = New MailAddress("myfriend@hotmail.com")
MyEmail.To.Add(ToAddress)

Dim CCAddress = New MailAddress("myotherfriend@tepidmail.com")
MyEmail.CC.Add(CCAddress)

Dim BccAddress = New MailAddress("mysecretfriend@coldmail.com")
MyEmail.Bcc.Add(BccAddress)
...

MyClient.Send(MyEmail)
Listing 10-50. Code to create MailAddresses for assignment to a MailMessage's CC and Bcc properties.

The Subject Property

A MailMessage has a Subject property representing the subject line of an email message. A subject-line string is assigned directly to this property using the following formats.

Dim SubjectLine As String
SubjectLine = "subject string"
MailMessage.Subject = SubjectLine

or

Dim SubjectLine As String = "subject string"
MailMessage.Subject = SubjectLine

or

MailMessage.Subject = "subject string"
Figure 10-42. General formats to create a MailMessage subject line.
Dim MyEmail = New MailMessage
Dim MyClient = New SmtpClient("localhost")

Dim FromAddress = New MailAddress("dadams@mail.maconstate.edu")
MyEmail.From = FromAddress

Dim ToAddress = New MailAddress("myfriend@hotmail.com")
MyEmail.To.Add(ToAddress)

Dim CCAddress = New MailAddress("myotherfriend@tepidmail.com")
MyEmail.CC.Add(CCAddress)

Dim BccAddress = New MailAddress("mysecretfriend@coldmail.com")
MyEmail.Bcc.Add(BccAddress)

MyEmail.Subject = "This is the subject line"
...

MyClient.Send(MyEmail)
Listing 10-51. Code to create a MailMessage subject line.

The Body Property

A MailMessage has a Body property representing the main body of an email message. A message string is assigned directly to this property using the following formats.

Dim MailBody As String
MailBody = "text and XHTML string"
MailMessage.Body = MailBody

or

Dim MailBody As String = "text and XHTML string"
MailMessage.Body = MailBody

or

MailMessage.Body = "text and XHTML string"
Figure 10-43. General formats to create a MailMessage's Body content.
Dim MyEmail = New MailMessage
Dim MyClient = New SmtpClient("localhost")

Dim FromAddress = New MailAddress("dadams@mail.maconstate.edu")
MyEmail.From = FromAddress

Dim ToAddress = New MailAddress("myfriend@hotmail.com")
MyEmail.To.Add(ToAddress)

Dim CCAddress = New MailAddress("myotherfriend@tepidmail.com")
MyEmail.CC.Add(CCAddress)

Dim BccAddress = New MailAddress("mysecretfriend@coldmail.com")
MyEmail.Bcc.Add(BccAddress)

MyEmail.Subject = "This is the subject line"

MyEmail.Body = "This is the content of the email message."

MyClient.Send(MyEmail)
Listing 10-52. Code to create a MailMessage's message body.

Finally, the point has been reached where all required components of a MailMessage have been declared and assigned to the MailMessage object. Now it is a matter of sending the MailMessage through the SmtpClient.

It is likely that the body of the message will contain more text than can be coded in a single string assignment. You can, though, concatenate any number of text strings to the Body property: MailMessage.Body &= "next text string", etc. A better way, however, is to build the body of the message in a separate string variable and assign the variable to the Body property prior to sending the message.

Dim BodyString As String = ""

BodyString &= "First sentence of message. "
BodyString &= "Second sentence of message. "
BodyString &= "Third sentence of message. "
BodyString &= "Last sentence of message."

MailMessage.Body = BodyString
Listing 10-53. Composing a message string for assignment to the MailMessage's Body property.

Message Formatting

Unless specified otherwise, the email message is sent as ASCII text, without formatting. Often you will wish to produce messages that are formatted as HTML pages, including XHTML tags to structure and style the message. This is easily accomplished by including tags inside the message strings and by setting the MailMessage's IsBodyHtml="True" property.

Dim BodyString As String = ""

BodyString &= "<h3>My Message</h3>"
BodyString &= "<p>"
BodyString &= "First line of message.<br/>"
BodyString &= "Second line of message.<br/>"
BodyString &= "Third line of message.<br/>"
BodyString &= "Last line of message.<br/>"
BodyString &= "</p>"

MailMessage.Body = BodyString
MailMessage.IsBodyHtml = "True"
Listing 10-54. Composing an HTML-formatted message string for assignment to the MailMessage's Body property.

Message Priority

You can set a MailMessage's priority by assigning one of three priority levels to its Priority property. The levels are MailPriority.High, MailPriority.Normal, and MailPriority.Low.

MailMessage.Priority = MailPriority.High
Listing 10-55. Setting a MailMessage's priority level.

Message Attachments

One or more attachments can be added to a MailMessage. First, an Attachment object is created giving the path to the file to be attached to the message. Then, this Attachment object is added to the MailMessage's Attachments collection. The path to the attachment file is its physical path on the server. You can use the Server.MapPath() method to convert a relative path to a physical path.

Dim AttachmentFile As Attachment
AttachmentFile = New Attachment(path)
MailMessage.Attachments.Add(AttachmentFile)

or

Dim AttachmentFile = New Attachment(path)
MailMessage.Attachments.Add(AttachmentFile)

or

MailMessage.Attachments.Add(New Attachment(path))
Figure 10-44. General formats to create an attachment for a MailMessage.

In the following example, a Picture.gif file located in the same directory as the page sending the email is added as an attachment.

Dim MyAttachment = New Attachment(Server.MapPath("Picture.gif"))
MailMessage.Attachments.Add(MyAttachment)
Listing 10-56. Code to add an attachment to a MailMessage.

As you can infer from the Add() method, any number of attachments of any file types can be added to the Attachments collection to be sent along with the email message.

Sending Email with Attachments

When creating an email application for Web users, it is often the case that you need to make provision for users to attach their own files to an email. That is, the user selects one or more files from their local computers for appending to the email. In this case, it is necessary to first upload the files to the Web server (where they are accessible by ASP.NET) and then attach these files to the email message.

In the following example, a file upload feature is added to an email composition form. You can use this form to email yourself a message with attachments.

Send Email with Attachments

To:
From:
Subject:
Message:
Attachments:



Figure 10-45. Sending an email with attachments through a form.

In the following code listing, an <asp:FileUpload> control is added to the form along with a Label display area to echo the names of the files selected for upload and attachment to the email message.

<h3>Send Email with Attachments</h3>

<table id="EmailTable" border="0" style="border-collapse:collapse">
<tr>
  <th>To:</td>
  <td><asp:TextBox id="MailTo" Width="200" Runat="Server"/></td>
</tr>
<tr>
  <th>From:</td>
  <td><asp:TextBox id="MailFrom" Width="200" Runat="Server"/></td>
</tr>
<tr>
  <th>Subject:</td>
  <td><asp:TextBox id="Subject" Width="300" Runat="Server"/></td>
</tr>
<tr>
  <th>Message:</td>
  <td><asp:TextBox id="Body" Runat="Server"
      TextMode="MultiLine" Rows="5" Width="300"
      Font-Name="Arial"/></td>
</tr>
<tr>
  <th>Attachments:</td>
  <td><asp:FileUpload id="FileUp" Width="250px" Runat="Server"/>
      <asp:Button Text="Attach" OnClick="Upload_File" Runat="Server"/><br/>
      <asp:Label id="Attachments" Width="300" Runat="Server"/>
  </td>
</tr>
</table>
<br/>
<asp:Button Text="Send Email" OnClick="Send_Email" Runat="Server"/>
<asp:Label id="MailMsg" ForeColor="#FF0000" Runat="Server"/>
Listing 10-57. Code to upload files as email attachments.

Uploading Files for Attachment

When the "Attach" button is clicked, subprogram Upload_File is called to upload the chosen file to the server. Here it is assumed that a directory named Attachments has been created for storing files uploaded as email attachments. The file name is concatenated to the display Label as visual feedback that the file has been uploaded. Any number of files can be uploaded.

<%@ Import Namespace="System.Net.Mail" %>
<%@ Import Namespace="System.IO" %>

<SCRIPT Runat="Server">

Sub Upload_File (Src As Object, Args As EventArgs)

  If FileUp.HasFile Then
    FileUp.SaveAs(Server.MapPath("../Attachments/") & FileUp.FileName)
    Attachments.Text &= FileUp.FileName & "<br/>"
  End If

End Sub
...

</SCRIPT>
Listing 10-58. Script to uploaded files to Attachments directory.

Adding Files to the Attachments Collection

The "Send Mail" button calls subprogram Send_Mail to send the composed message along with any files uploaded to the Attachments directory. A new MailMessage and SmtpClient object are created, with information from the form assigned as the From, To, Subject, and Body properties of the message. Then, the uploaded files are assigned as attachments to the message.

<%@ Import Namespace="System.Net.Mail" %>
<%@ Import Namespace="System.IO" %>

<SCRIPT Runat="Server">

Sub Upload_File (Src As Object, Args As EventArgs)
  ...
End Sub

Sub Send_Email (Src As Object, Args As EventArgs)

  If MailFrom.Text <> "" _
     AND MailTo.Text <> "" _
     AND Subject.Text <> "" _
     AND Body.Text <> "" Then
		
    Dim MailClient = New SmtpClient("localhost")
    Dim Email = New MailMessage
    Dim FileArray() As String
    Dim FileItem As String
    
    Try
    
    Email.From = New MailAddress(MailFrom.Text)
    Email.To.Add(New MailAddress(MailTo.Text))
    Email.Subject = Subject.Text
    Email.Body = Body.Text
    Email.IsBodyHtml = True
    
    If Attachments.Text <> "" Then
      FileArray = Directory.GetFiles(Server.MapPath("../Attachments/"))
      For Each FileItem in FileArray
        Email.Attachments.Add(New Attachment(FileItem))
      Next
    End If
    
    MailClient.Send(Email)
    MailMsg.Text = "Email sent"
    
    Catch
      MailMsg.Text = "Error in sending email!"
    End Try
    
    If Attachments.Text <> "" Then
      Email.Attachments.Dispose()
      FileArray = Directory.GetFiles(Server.MapPath("../Attachments/"))
      For Each FileItem in FileArray
        File.Delete(FileItem)
      Next
    End If
    
    MailFrom.Text = ""
    MailTo.Text = ""
    Subject.Text = ""
    Body.Text = ""
    Attachments.Text = ""
    
  End If

End Sub
	
</SCRIPT>
Listing 10-59. Script to attach uploaded files to an email message.

The Directory.GetFiles() method retrieves all files in the Attachments directory (thus, the need for the System.IO namespace). The list of files is iterated and each file, in turn, becomes a new Attachment object in the MailMessage's Attachments collection.

Email.Attachments.Add(New Attachment(FileItem))

Finally, the email is sent through the SmtpClient. Notice that creation and sending of the email is enclose in a Try...Catch structure in order to trap any errors associated with sending the email.

Deleting Attachment Files

Once the email has been sent, there is no reason to retain the files previously uploaded to the Attachments directory. So, these files are deleted before exiting the subprogram. It is important to remember, however, that the MailMessage's Attachments collection is still associated with the MailMessage object, even after the email is sent. If an attempt is made to delete the files while this relationship still exists, an error is generated to the effect that the files cannot be deleted because they are still in use. Therefore, it is necessary apply the Dispose() method of the Attachments collection to release it for deletion.

Email.Attachments.Dispose()

Now, the File.Delete() method can be used to delete all files in the Attachments directory. Also, all of the form fields are blanked in preparation for a new message.

In this example, a single Attachments directory is used for all uploads and attachments. This works as long as a single user at a time sends an email. With multiple users, however, files belonging to different people are intermixed and you may end up deleting files that have been uploaded but not yet attached and mailed. A better solution is to create different attachment directories, as needed and in script, to service different users.