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.
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" %>
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)
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)
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>
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.
<%@ 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>
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
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)
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)
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)
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))
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)
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)
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)
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"
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)
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"
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)
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
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"
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
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))
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)
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.
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"/>
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>
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>
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.