Last update on 2nd August 2008 @ 21:30

We all know, that Micro Framework can't have all the features of full .NET Framework. One thing I really missing (and not only me) is SmtpClient class that would allow sending emails using Simple Mail Transfer Protocol (SMTP). If you look at the SMTP specification you will find very easy comuinication protocol - it's just text commands. Command <CR><LF> there, response <CR><LF> back - that's all.

This brought me on idea of writing my own implementation of SmtpClient class for .NET Micro Framework. I've decide to be as much compatible as possible with the "desktop" version of System.Net.Mail.SmtpClient class. Look how easy can be sending e-mails from .NET Micro Framework.

using (SmtpClient smtp = new SmtpClient("smtp.hostname.net", 25))
{
    // Send message
    smtp.Send("john@doe.com",
              "foo@bar.net",
              "Good news",
              "How are you Foo?");
}

Bansky.SPOT.Mail class library

Send simple e-mail using SMTP is quite easy; BUT. Nowadays most of the SMTP server requires authentication. It means, that SmtpClient without authentication would be a bit useless. And here starts the fun. SMTP authentication needs Base64 encoded username and password. Damned, Base64 is not supported in Micro Framework. So, the first task is to obtain Base64 encoding / decoding class. Once you can encode data into Base64, you can code data for e-mail attachments as well. Let's implement System.Net.Mail.Attachment class. More functionality needs more complex exception handling. Ok, add the System.Net.Mail.SmtpException class.

After few days you wake up and see, that you have ended up with complete class library for e-mailing. That's how I create Bansky.SPOT.Mail class library.

Base64, Authentication and bug in Micro Framework

When SMTP server requires authentication, client start session with command EHLO domain.com. Server responds with supported methods of authentication. Simply said, encoding methods of the credentials. Most SMTP servers supports PLAIN or LOGIN method or both; if not, my SmtpClient will end up with exception. There are other authentication methods like CRAM-MD5 and CRAM-SHA1.

Authentication information for PLAIN method is this string "\0username\0password" encoded in Base64. Problem is, that Micro Framework in version 2.5 (and less) interprets "\0" as an end of the string. It means that PLAIN authentication string is interpreted as empty string. Characters after "\0" are ignored. And this leads to workaround. First I convert string of " username password" into byte array and then replace appropriate spaces with the 0x00 byte. Such a byte array is input for Base64.Encode() method.

It's important to say that the core of Base64 class is based on Base64Encoder class from Timm Martin. I've just added the methods for splitting encoded data into lines of 76 bytes as it's required by MIME specification.

Following code shows how to set authentication credentials to SmtpClient class. Authentication method will be automatically chosen according to server capabilities.

using (SmtpClient smtp = new SmtpClient("smtp.hostname.net", 25))
{
    // Create message
    MailMessage message = new MailMessage("john@doe.com",
                                          "foo@bar.net",
                                          "Good news",
                                          "How are you Foo?");

    // Authenicate to server
    smtp.Authenticate = true;
    smtp.Username = "userlogin";
    smtp.Password = "userpassword";

    // Send message
    smtp.Send(message);
}

E-mail attachments

Besides HTML formated messages, my MailMessage implementation supports attachments. E-mail attachment can be any binary data, which will be processed using Base64 encoding and added into multipart MIME message. Example of message with attachment is below.

WARNING: encoding binary data into base64 in .NET Micro Framework can be extremely time and resource consuming. It means, that the larger the data is, the more time it takes to process it; and if I say "more time", I mean really long time. So, be careful and don't be surprised.

MailMessage message = new MailMessage();
// Set sender name and address
message.From = new MailAddress("foobar@contoso.com", "Foo Bar");

// Set recipients
message.To.Add(new MailAddress("john.doe@customer.com", "John Doe"));
message.Cc.Add(new MailAddress("manager@contoso.com"));

message.Subject = "Hello World";
message.Body = "from now on you can send e-mails from <b>.NET Micro Framework</b>.";
// Format body as HTML
message.IsBodyHtml = true;

// Create new attachment and define it's name
Attachment attachment = new Attachment("Snwoflake.gif");        
attachment.ContentType = "image/gif";
attachment.TransferEncoding = TransferEncoding.Base64;
// Attachment content
attachment.Content = Base64.Encode( Resources.GetBytes(
                                    Resources.BinaryResources.Snowflake_gif),
                                    true);

// Add attachment to message
message.Attachments.Add(attachment);

// Create new SMTP instance
SmtpClient smtp = new SmtpClient("smtp.contoso.com", 25);
try
{
    // Authenicate to server
    smtp.Authenticate = true;
    smtp.Username = "userlogin";
    smtp.Password = "userpassword";

    // Send message
    smtp.Send(message);
}
catch (SmtpException e)
{
    // Exception handling here 
    Debug.Print(e.Message);
    Debug.Print("Error Code: " + e.ErrorCode.ToString());
}
finally
{
    smtp.Dispose();
}

Additional headers

Every mail message contains header, that specifies informations like date when message was created, sender name etc. If you want to put additional information into header you can use Headers property. See example below.

MailMessage message = new MailMessage("john@doe.com",
                                      "foo@bar.net",
                                      "Good news",
                                      "How are you Foo?");

message.Headers = "X-Priority: 1\r\n";
message.Headers += "X-MSMail-Priority: High\r\n";
message.Headers += "X-Mailer: Micro Framework mail sender\r\n";

Exception handling

Besides standard exceptions like ArgumentNullException and ArgumentOutOfRangeException, there are also SmtpException thrown by Send method of SmtpClient. SmtpException in full framework contains StatusCode property, which describes status where exception occured. Since my Send method is not so rich, I've replaced StatusCode with ErrorCode, that describes the reason of exception. The SmtpErrorCode enum contains values like BarResponse, AuthFailed, ConnectionFailed and so on.

Demo and Download

Complete library with sources, documentation and sample application are available for download. Library was tested in emulator and GHI Embedded Master module.

Download: EmailDemo_NETMF.zip [228 Kb]