Search Forum
(53671 Postings)
Search Site/Articles

Archived Articles
712 Articles

C# Books
C# Consultants
What Is C#?
Download Compiler
Code Archive
Archived Articles
Advertise
Contribute
C# Jobs
Beginners Tutorial
C# Contractors
C# Consulting
Links
C# Manual
Contact Us
Legal

GoDiagram for .NET from Northwoods Software www.nwoods.com


 
Printable Version

HowTo SMTP in C#
By Randy Charles Morin

This series of articles is written to show the user how to write TCP/IP based client applications using C# on Microsoft's new dotNET framework. This is the first article in this series.

The first killer applications on the Internet were email and netnews. Email on the Internet was developed using two simple Internet protocols, SMTP and POP3. The first two articles in this series, I'll present to you two classes for implementing SMTP and POP3 clients. In the third article in this series, I'll present to you one class for implementing a NNTP client.

The SMTP or Simple Mail Transfer Protocol is described in RFC 821 [http://www.ietf.org/rfc/rfc0821.txt]. This application protocols is used to send email over the Internet. A few years back, I wrote two articles on sending SMTP messages in C++ [http://www.kbcafe.com/articles/smtp.html] [http://www.kbcafe.com/articles/html.smtp.html]. This article shows how to do the same programming in Microsoft's new C# language.

The dotNET framework already contains an SMTP class in the System.Web.Mail namespace called SmtpMail. This class is sufficient for sending email over the Internet and I would not suggest that the class I'm presenting in this article is any better or worse. Let's just say that it is different. If you can get away with using the dotNET SmtpMail class, then I suggest you do just that. The only advantage of my class is that it is open source and let me suggest that the SmtpMail class in dotNET has a few more features.

My motivation in writing this article is not to try and write a better SMTP class, but rather to show how to write TCP/IP based clients in C#. And here goes.

I started by writing a custom exception for my C# Smtp class. Whenever my C# class encounters faults, I'll throw an instance of this exception. The exception class is presented in Listing 1.

Listing Error! Bookmark not defined.: Exception Class

public class SmtpException : System.Exception

{

private string message;

public SmtpException(string str)

{

message = str;

}

public string What()

{

return message;

}

};

 

Our class will be inherited from the System.Net.Socket.TcpClient class in the dotNET framework. This class provides all the base functionality that is required to do TCP/IP programming. Our class declaration is presented in Listing 2.

Listing Error! Bookmark not defined.: Class Declaration

public class Smtp : System.Net.Sockets.TcpClient

 

Our class will have eight data members. The from data member is the sender of the email. The to, cc and bcc data members represent the recipients of the email. The subject data member is the subject of the email. Either bodyText or bodyHtml will represent the body of the email. The server data member represents the SMTP server where our client is sending the message. The data member definitions are presented in Listing 3.

Listing Error! Bookmark not defined.: Data Members

public class Smtp : System.Net.Sockets.TcpClient

{

public string from = null;

public ArrayList to;

public ArrayList cc;

public ArrayList bcc;

public string subject = null;

public string bodyText = null;

public string bodyHtml = null;

public string server = null;

 

The to, cc and bcc data members are arrays, in order to allow multiple recipients of all three types. All three arrays must be created in the constructor of our class. The constructor of our class is presented in Listing 4.

Listing Error! Bookmark not defined.: Constructor

public Smtp()

{

to = new ArrayList();

cc = new ArrayList();

bcc = new ArrayList();

}

 

The Send method does all the work in our class. Once you've set the subject, body, from and recipient data members, you simply call the Send method and the SMTP communication is initiated. I wont' explain the details of the SMTP protocol here, but rather encourage the user to step through the code, read the SMTP RFC and read my previous articles on SMTP. The Send method is presented in Listing 5.

Listing Error! Bookmark not defined.: Send Method

public void Send()

{

string message;

string response;

 

Connect(server, 25);

response = Response();

if (response.Substring(0, 3) != "220")

{

throw new SmtpException(response);

};

 

message = "HELO me\r\n";

Write(message);

response = Response();

if (response.Substring(0, 3) != "250")

{

throw new SmtpException(response);

}

 

message = "MAIL FROM:<" + from + ">\r\n";

Write(message);

response = Response();

if (response.Substring(0, 3) != "250")

{

throw new SmtpException(response);

}

 

foreach ( string address in to )

{

try

{

message = "RCPT TO:<" + address + ">\r\n";

Write(message);

response = Response();

if (response.Substring(0, 3) != "250")

{

throw new SmtpException(response);

}

}

catch( SmtpException e)

{

System.Console.WriteLine("{0}", e.What());

}

}

 

foreach ( string address in cc )

{

try

{

message = "RCPT TO:<" + address + ">\r\n";

Write(message);

response = Response();

if (response.Substring(0, 3) != "250")

{

throw new SmtpException(response);

}

}

catch( SmtpException e)

{

System.Console.WriteLine("{0}", e.What());

}

}

 

foreach ( string address in bcc )

{

try

{

message = "RCPT TO:<" + address + ">\r\n";

Write(message);

response = Response();

if (response.Substring(0, 3) != "250")

{

throw new SmtpException(response);

}

}

catch( SmtpException e)

{

System.Console.WriteLine("{0}", e.What());

}

}

 

message = "DATA\r\n";

Write(message);

response = Response();

if (response.Substring(0, 3) != "354")

{

throw new SmtpException(response);

}

 

message = "Subject: " + subject + "\r\n";

foreach ( string address in to )

{

message += "To: " + address + "\r\n";

}

 

foreach ( string address in cc )

{

message += "Cc: " + address + "\r\n";

}

 

message += "From: " + from + "\r\n";

if (bodyHtml.Length > 0)

{

message += "MIME-Version: 1.0\r\n"

+"Content-Type: text/html;\r\n"

+" charset=\"iso-8859-1\"\r\n";

message += "\r\n" + bodyHtml;

}

else

{

message += "\r\n" + bodyText;

};

message += "\r\n.\r\n";

Write(message);

response = Response();

if (response.Substring(0, 3) != "250")

{

throw new SmtpException(response);

}

 

message = "QUIT\r\n";

Write(message);

response = Response();

if (response.IndexOf("221") == -1)

{

throw new SmtpException(response);

}

}

 

The Send method uses three methods, the Connect, Write and Response methods. The Connect method is inherited from the TcpClient class and establishes a TCP connection between our client and a TCP server. The other two methods are implemented in our class and described in the next paragraphs.

The Write method writes data to the socket. The Write method is presented in Listing 6.

Listing Error! Bookmark not defined.: Write Method

public void Write(string message)

{

System.Text.ASCIIEncoding en = new System.Text.ASCIIEncoding() ;

 

byte[] WriteBuffer = new byte[1024] ;

WriteBuffer = en.GetBytes(message) ;

 

NetworkStream stream = GetStream() ;

stream.Write(WriteBuffer,0,WriteBuffer.Length);

}

 

It must be remembered that C#'s native string type is not based on the ASCII characters, but rather is based on Unicode. Thus in order to send messages on SMTP we must first convert the string input parameter to an array of ASCII bytes. We use the ASCIIEncoding class in dotNET to make this transformation. Then we retrieve the socket stream using the GetStream method inherited from the TcpClient class and write the bytes to the stream.

The Response method receives data from the socket. The Response method is presented in Listing 7.

Listing Error! Bookmark not defined.: Response Method

public string Response()

{

System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();

byte []serverbuff = new Byte[1024];

NetworkStream stream = GetStream();

int count = stream.Read( serverbuff, 0, 1024 );

if (count == 0)

{

return "";

}

return enc.GetString( serverbuff, 0, count );

}

 

The Response method begins by retrieving the bytes from the stream and then converts the incoming ASCII bytes to our native C# string type.

Now that we have an SMTP class, you might be wondering how you use it. To send an SMTP message, you simply instantiate an instance of the class, set the appropriate data members and call the Send method.

Listing Error! Bookmark not defined.: Usage

static void Main(string[] args)

{

try

{

kbcafe.Smtp smtp = new kbcafe.Smtp();

smtp.server = "smtp.xxx.com";

smtp.from = "yyy@xxx.com (zzz)";

smtp.subject = "Hello World";

smtp.bodyHtml = "<HTML><BODY>Hello World</BODY></HTML>";

smtp.to.Add("yyy@xxx.com");

smtp.Send();

}

catch( kbcafe.SmtpException e)

{

System.Console.WriteLine("{0}", e.What());

}

}

 

If you reuse this code, replace the xxx, yyy and zzz parameters by valid values. A valid from address may be "randy@kbcafe.com (Randy Charles Morin)". Please don't use this address, I get enough emails already.

About the Author

Randy Charles Morin is the Chief Architect of SportMarkets Development from Toronto, Canada and lives with his wife, Bernadette and two kids, Adelaine and Brayden in Brampton, Canada. He is the author of the KBCafe.com website [http://www.kbcafe.com], many programming books and many articles.

Copyright 2002-03 Randy Charles Morin