Getting E-Mail Out the Door
Having looked at how to prepare an e-mail object, Peter turns his attention to getting the message mailed to someone.
In a previous column ("The MailMessage Always Delivers
"), I showed how you can create an e-mail message complete with attachments and multiple recipients using the MailMessage object. Of course, creating a message is no help to you unless you can send it -- which is the responsibility of the SmtpClient object. In fact, by using the SmtpClient, you can bypass creating a MailMessage object altogether for simple e-mails.
.NET doesn't include an e-mail management system. Instead, the SmtpClient (found in the System.Net.Mail namespace, not in the System.Web.Mail namespace) lets you pass an e-mail to your e-mail management system to be mailed. When you create the SmtpClient, you can specify the URL or TCP/IP address of your SMTP server. This example references a server at "mail.company.com".
Once you've created your SmtpClient object, you can send an e-mail just by providing "to" and "from" addresses, a subject and a body, as this example does:
"A subject line", _
"The body of the e-mail")
If you want to create a more complicated e-mail (e.g., one with an attachment) you can just pass a MailMessage object (as described in more detail in the earlier column).
Many SMTP servers require users to provide some credentials (a user name and password) before they'll accept mail. You can pass credentials to the SMTP server one of three ways.
First, if the SMTP server is set up to recognize the user ID that ASP.NET is running under (typically "ASPNET" or "Network Service") then you can just pass the default credentials for the site. To trigger that behavior, just set the SmtpClient's UseDefaultCredentials property to True before calling the send method.
However, if you prefer, you can generate a set of credentials in your code by creating a NetworkCredential object and using it to set the SmtpClient object's Credentials property. This example logs on with the user ID "Fuller" and the password "abc123$".
If you're uncomfortable with embedding user IDs in your code, you can put the credentials in your web.config file where they can be encrypted by adding these tags (this example sets the "from" address, the server address, and the user ID and password):
<network host="mail.mysite.com" userName="Fuller"
If you have a slow connection to your SMTP server, you can use an asynchronous send which doesn't wait for the SMTP server to respond. Be aware: You can't send another e-mail until the first e-mail has finished processing, so you can't use this method to improve responsiveness when sending multiple e-mails.
The asynchronous send requires one final, extra parameter compared to the standard Send method, which can be anything you want. This example sends a MailMessage object with the extra parameter set to "My Message":
client.SendAsync(mm, "My Message")
You'll also need to enable asynchronous operations for your page. I do that in the page directive in the .ASPX file by adding the Async attribute and setting it to true:
<%@ Page Language="VB" Async="true"...
You should probably check to see if your e-mail was sent successfully. To enable that, you'll need to declare your SmtpClient as a class-level variable using the WithEvents keyword:
Private WithEvents client As System.Net.Mail.SmtpClient
You can now catch the SendCompleted event that's fired when your send request finishes processing (either it succeeds or fails). The skeleton for the event handler looks like this.
The skeleton that's generated for you won't include the Shared keyword, so you'll have to add that yourself. There's a real possibility that this event will be fired after the rest of the code in your page has finished processing and has been removed from memory. Adding Shared to the method's signature allows the method to be called from the page's class without needing an instance of the page to be in memory.
Two properties on the e parameter are useful here: Error and UserState. If something goes wrong with your e-mail transmission, the Error property will have an Exception object that will tell you what happened; the UserState property will have that extra, final parameter you passed to the SendAsync method so you can determine which e-mail wasn't transmitted. If you do have an error, you can't assume that the page you sent the e-mail from is still available so you'll have to settle for writing the message out to a log file.
Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.