About

I'm Mike Pope. I live in the Seattle area. I've been a technical writer and editor for over 35 years. I'm interested in software, language, music, movies, books, motorcycles, travel, and ... well, lots of stuff.

Read more ...

Blog Search


(Supports AND)

Feed

Subscribe to the RSS feed for this blog.

See this post for info on full versus truncated feeds.

Quote

People studying literature rarely say anything that would be of the slightest use to those producing it.

Paul Graham



Navigation





<February 2025>
SMTWTFS
2627282930311
2345678
9101112131415
16171819202122
2324252627281
2345678

Categories

  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  

Contact Me

Email me

Blog Statistics

Dates
First entry - 6/27/2003
Most recent entry - 9/4/2024

Totals
Posts - 2655
Comments - 2677
Hits - 2,727,050

Averages
Entries/day - 0.34
Comments/entry - 1.01
Hits/day - 345

Updated every 30 minutes. Last: 1:34 PM Pacific


  06:29 PM

One of the changes for ASP.NET 2.0 is that the class(es) for sending email messages have been enhanced. For starters, they're not in System.Web, coz that's a silly place for them to be; instead, they're in System.Net. I've also known, vaguely, that there have been additional enhancements to support functionality that was not previously available, such as embedding files (graphics), sending credentials, SSL support, et.. I thought I should look into this, because it won't be long before I'll be using 2.0 and sending emails (I assume the old classes still work, tho).

But I thought I'd start with just sending a simple email. And I thought it would be an interesting exercise to see if I could figure out how to do it without any documentation, just using the IDE -- specifically, IntelliSense and real-time compilation validation. (Since I'm a VB guy.) So here's how it went.

I knew that the message itself would be a class. So I started with Dim msg As New and then let IntelliSense help me figure out that I wanted System.Net.Mail.MailMessage. I admit this is a slightly unfair advantage over the total noob, in that I at least knew roughly what namespace to look in. Anyway, I started with:
Dim msg As New System.Net.Mail.MailMessage()
To set the From address, I typed this:
msg.From = "mike@elsewhere.com"[1]
Nope. The editor squiggles "From" and tells me "Value of type 'String' cannot be converted to System.Net.Mail.MailAddress." Aha. Addresses must be types now. I quick-like import System.Net.Mail to save some effort. Then using IntelliSense I hunt around for a likely-sounding type for addresses and end up with this:
Dim fromAddress As New MailAddress()
fromAddress.Address = "mike@elsewhere.com"
Error: Property 'Address' is Read-Only.

Hmm. Wonder why. Ok, I bet I can pass it in the constructor:
Dim fromAddress As New MailAddress("mike@elsewhere.com")
That works. Cycling through the overloads, I learn that I can also set a display name:
Dim fromAddress As New MailAddress("mike@elsewhere.com", "Mike")
I figure the To address must be similar, so I do this:
Dim msg As New MailMessage()
Dim fromAddress As New MailAddress("mike@elsewhere.com", "Mike")
Dim toAddress As New MailAddress("mike@work.com", "Mike")
msg.From = fromAddress
msg.To = toAddress
Now msg.To is squiggled: "Property 'To' is Read-Only."

Oh for heaven's sake. Why is From settable but To is not? I retrace and try overloads again, which yields this:
Dim fromAddress As New MailAddress("mike@elsewhere.com", "Mike")
Dim toAddress As New MailAddress("mike@work.com", "Mike")
Dim msg As New MailMessage(fromAddress, toAddress)
Editor does not complain. On to the rest of the message! Using hints from IntelliSense, I construct this:
msg.Body = "<b>Testing new email</b>"
msg.Subject = "Testing new email"
msg.IsBodyHtml = True
I guess that's enough actual message. I want to send my message now, and I notice the lack of two members I was expecting: a property to set the SMTP server name, and a send method. Those obviously belong to another class, so it's back to IntelliSense.

I peer through the classes in System.Net.Mail and try a few. Ultimately I decide that SmtpClient seems like the most promising, so I create this:
Dim mailSender As New System.Net.Mail.SmtpClient()
The overloads allow me to specify host and port, which makes it seem like the right thing. I now have this:
Dim mailSender As New System.Net.Mail.SmtpClient()
mailSender.Host = "(hostName)"
I look through the other members of the SmtpClient class. A property named DeliveryMethod looks like it might be useful. IntelliSense offers me three enums for this property:
SmtpDeliveryMethod.Network
SmtpDeliveryMethod.PickupDirectoryFromIis
SmtpDeliveryMethod.SpecifiedPickupDirectory
Arg. Man, I don't know. Our mail host is across the network, so that seems like a good choice. (Is it the default?) But perhaps it's an IIS-based SMTP virtual server; in that case, do I need to explictly specify a pickup directory? (Seems like that, too, would be defaulted.) Well, I'll just try sending it without setting the DeliveryMethod property and see what happens. I'm pretty sure that the SmtpClient class must have a Send method. Whoa, it sure does -- it has three of them:
Send
SendAsynch
SendAsynchCancel
I deduce (aren't I the brilliant one) that Send is synchronous. I know that asynch methods generally require creating a callback delegate or something, and although it's possible I could do that, I don't need to right now. But it's duly noted for future reference.

Curiously, the SmtpClient class has no obvious property for specifying which message to send. But once again IntelliSense rescues me and informs me that I can pass the message as an argument to the Send method.

Since I have no idea if any of this is going to work, I figure I'll put the Send method in a Try block and dump whatever errors the Catch block produces. Who knows, if it doesn't work, I might learn something. So now I have this:
Try
mailSender.Send(msg)
Label1.Text = "Message sent."
Catch ex As Exception
Label1.Text = ex.Message
End Try
Shall we try it? Do let's. Compilation works, which I expected, since there were no squiggles. But I get this error, which makes me glad I used the Try/Catch block:

Mailbox unavailable. The server response was 5.7.1. Unable to relay for (name).

I had used one of my non-work email addresses as the From address. Perhaps that's it? I change From and To to be the same (work) email address. Nope, same error.

Hmm. Hmm. A little googling to learn what the 5.7.1 error is, from which I deduce that the Exchange server is refusing to relay for anyone not in its domain. So I look again at the From and To addresses. Ok, well, one problem is that I misspelled the From address. A few more experiments, and I learn that our internal relay server will send only from and to addresses within our domain. (Or so it seems.)

Anyway, now it works. Here's the complete code as constructed entirely with IntelliSense and some help from the compiler squiggles:
Dim fromAddress As New MailAddress("mike@work.com", "Mike @ work")
Dim toAddress As New MailAddress("mike@work.com", "Mike @ work")
Dim msg As New MailMessage(fromAddress, toAddress)
msg.Body = "<b>Testing new email</b>"
msg.Subject = "Testing new email, sent at " & DateTime.Now.ToString()
msg.IsBodyHtml = True

Dim mailSender As New System.Net.Mail.SmtpClient()
mailSender.Host = "(hostname)"
Try
mailSender.Send(msg)
Label1.Text = "Message sent."
Catch ex As Exception
Label1.Text = ex.Message
End Try
[1] Actual email address changed to protect the ... well, to protect me.

[categories]   ,

[5] |