Sending an e-mail is pretty old news by now so it should come as no surprise that .NET contains a significant SMTP mail client. One old programming truth still holds: All programs will expand to eventually include sending (and receiving) e-mails. So how about adding e-mail to your program ? This post explores how we can use the System.Mail.SmtpClient to send formatted e-mails. There are plenty of options available and we will explore most of them.
In another lifetime together with friends I wrote a massive e-mail parser for the then popular FidoNet, and the (for us) new RFC822 based Internet. Written in Pascal for DOS it chewed its way through megabytes of modem downloaded Usenet groups and e-mail for our local BBS, night after night. It was fun and I learned that when it comes to e-mail that there are no real standards, just broken implementations.
Some 15 years later things have become quite a bit easier. Sending an e-mail is as straightforward as calling a few basic library functions and .NET of course includes a solid implementation.
Quickly sending an e-mail
If you are in a hurry then the following constructor will create a simple mail message from just 4 string parameters:
// public client.Send(string from,string to,string subject,string body) using System.Net.Mail; SmtpClient client = new SmtpClient(); client.Send("martijn@dijksterhuis.org","test@dijksterhuis.org","Testing!","If this break again,.. I won't know what to do");
In the above example the e-mail is send using the system default settings as discovered by the .NET framework. If you are curious which system acted as the Default SMTP server you can query SmtpClient.Host
Console.WriteLine(“Default SMTP Server: {0}”,client.Host);
Note that there is a good chance that the .NET libraries are unable to work out the SMTP host and will fail with an System.InvalidOperationException (The SMTP host was not specified) when you attempt to send the e-mail.
Sending a proper e-mail
An basic e-mail is build up out of a sender, one or more recipients, a message body and one or more attachments. And of course the e-mail is probably encoded in an outdated Russian font.
The e-mail sender and receiver are represented by the MailAddress class. So of course you need an e-mail address, optionally a name, and in case you really want to send a Russian formatted name, a proper encoding format.
MailAddress toUser = new MailAddress("martijn@dijksterhuis.org"); MailAddress toUser2 = new MailAddress("martijn@dijksterhuis.org","Martijn Dijksterhuis"); MailAddress toUser3 = new MailAddress("martijn@dijksterhuis.org","Martijn Dijksterhuis", System.Text.Encoding.UTF8);
My name doesn’t include any funky characters so I specified the default UTF-8 encoding.
Sending an e-mail with only a single sender and receiver
If your e-mail only contains a single sender and a single receiver the MailMessage(MailAddress From,MailAddress To) constructor provides all you need. It creates a new e-mail message structure, assigning the sending and receiver in the constructor.
MailAddress toUser = new MailAddress("myfriend@yahoo.com"); MailAddress fromUser = new MailAddress("martijn@dijksterhuis.org"); MailMessage msg = new MailMessage(fromUser,toUser);
Adding more receivers to the same e-mail
A single recipient is probably not sufficient. Not to worry, you can add as many To’s, CC’s, BCC’s etc to the e-mail as you would like:
msg.To.Add( new MailAddress("second_to@dijksterhuis.org") ); msg.CC.Add( new MailAddress("first_cc@dijksterhuis.org") ); msg.CC.Add( new MailAddress("second_cc@dijksterhuis.org") ); msg.Bcc.Add( new MailAddress("first_bcc@dijksterhuis.org") );
Setting the E-mail subject and body content
Setting the subject of the e-mail is not hard, just set it from Msg.Subject. And if you would like to encode that in a format other the Unicode, say BIG-5 Chinese:
msg.Subject = "一分鐘換一年" msg.SubjectEncoding = Encoding.GetEncoding("big5");
(The above Chinese came from my junk box and to the best of my knowledge its harmless)
Setting the actual message body works in a very similar fashion:
msg.Body = "Dear Customer, " + Environment.NewLine + Environment.NewLine; msg.Body += "Because of repeated violations of our terms and conditions we had no choice but to"; msg.Body += "terminate your account with us." + Environment.NewLine + Environment.NewLine; msg.Body += "The Management"; msg.BodyEncoding = System.Text.Encoding.UTF8;
Adding an attachment to the e-mail
An e-mail can have more than one attachment, and each attachment is represented by the System.Net.Mail.Attachment class. You can add them to the attachment collection of the message by calling “Attachments.Add()”
using System.Net.Mime; Attachment firstAttachment = new Attachment("document.doc",MediaTypeNames.Application.Octet); MailMessage msg = new MailMessage(fromUser,toUser); msg.Attachments.Add(firstAttachement);
The first parameter passed to the constructor is the path to the attachment to include. If no full path is given, the current working directory is tried. The file type is defined in System.Net.Mime — available options are:
MediaTypeNames | Application | Octet |
RTF | ||
Soap | ||
Zip | ||
Image | Gif | |
JPEG | ||
Tiff | ||
Text | HTML | |
Plain | ||
RichText | ||
XML |
If the type of file is not specified use MediaTypesNames.Application.Octet , which stands for “data is not interpreted”.
Adding custom e-mail headers to your e-mail
The Msg.Header property allows you to query and add to the e-mail headers set by the .NET framework. A brand new e-mail will only contain a single header: “Mime: 1.0″. Adding your own custom header to this is trivial as is shown in the following code example:
MailMessage Msg = new MailMessage(new MailAddress("martijn@dijksterhuis.org"),new MailAddress("martijn@dijksterhuis.org")); // Add a custom header to the e-mail Msg.Headers.Add("X-Header","2.0"); // Display all the message headers. string[] Keys = Msg.Headers.AllKeys; foreach (string s in Keys) Console.WriteLine("{0}: {1}", s,Msg.Headers[s]);
Sending your e-mail with SmtpClient
The hard work of delivering the e-mail is done through the SmtpClient class and the most basic delivery only takes two lines:
SmtpClient client = new SmtpClient();
client.Send(Msg);
It might be wise to catch exceptions at this point because sending an SMTP e-mail can throw a number:
- SmtpFailedRecipientsException: The message could not be delivered to one or more of the recipients in To, CC, or Bcc.
- SmtpException : Connection failed, authentication failed or a time-out
- ArgumentNullException / ArgumentOutOfRangeException / InvalidOperationException : Something wrong with the input fields of the e-mail
If you do not specify any parameters the default SmtpClient constructor will lookup the SMTP server to use through the .NET environment.
You can specify a specific server and optional port through the second constructor:
SmtpClient client = new SmtpClient(“mail.dijksterhuis.org”,3000);
The above SmtpClient.Send call is a blocking call — your application halts while the e-mail is being send. Naturally there is also an asynchronous call: SmtpClient.SendAsync.
Using SmtpClient.SendAsync is a little more work. How to do this is shown in the following example:
using System; using System.Net.Mail; using System.Threading; using System.ComponentModel; namespace SnmpMailer { class MainClass { static Semaphore mailSendSemaphore; private static void MailSendCallback(object sender, AsyncCompletedEventArgs arg) { // Get our unique token for this asynchronous operation. String token = (string) arg.UserState; // Did the user abort the sent ? if (arg.Cancelled) Console.WriteLine("[{0}] Send canceled.", token); // Did an error occur during the send? if (arg.Error != null) Console.WriteLine("[{0}] {1}", token, arg.Error.ToString()); else Console.WriteLine("Message sent succesfully!"); // Release the main thread mailSendSemaphore.Release(); } public static void Main(string[] args) { mailSendSemaphore = new Semaphore(0,1); /* Create the mail message with to & from */ MailMessage Msg = new MailMessage(new MailAddress("noreply@dijksterhuis.org"), new MailAddress("martijn@dijksterhuis.org")); Msg.Body = "Dear Customer, " + Environment.NewLine + Environment.NewLine; Msg.Body += "Because of repeated violations of our terms and conditions we had no choice but to"; Msg.Body += "terminate your account with us." + Environment.NewLine + Environment.NewLine; Msg.Body += "The Management"; Msg.BodyEncoding = System.Text.Encoding.UTF8; /* Set the subject */ Msg.Subject = "Termination of service notice"; /* Add our own header */ Msg.Headers.Add("X-Deliverator","Terminator"); /* Deliver the message in an asynchronous fashion */ SmtpClient Deliverator = new SmtpClient("mymailserver.com"); /* Print the default client */ Console.WriteLine("Default SMTP Server: {0}",Deliverator.Host); /* Specify the call back function */ Deliverator.SendCompleted += new SendCompletedEventHandler(MailSendCallback); /* For an asyncronous call we can pass a token to help us determine the message being send */ Deliverator.SendAsync(Msg,"Msg ID 1212"); /* Because we have little else to do, we set a semaphore and wait */ mailSendSemaphore.WaitOne(); Console.WriteLine("Mail delivery finished"); } } }
Image credit: Mzelle Biscotte
This is a post from Martijn's C# Coding Blog.