HowTo SMTP in C#
This series of articles is written toshow the user how to write TCP/IP based client applications using C# onMicrosoft's new dotNET framework. This is the firstarticle in this series.
The first killer applications on theInternet were email and netnews. Email on theInternet was developed using two simple Internet protocols, SMTP and POP3. Thefirst two articles in this series, I'll present to you two classes forimplementing SMTP and POP3 clients. In the third article in this series, I'llpresent to you one class for implementing a NNTP client.
The SMTP or Simple Mail Transfer Protocolis described in RFC 821 [http://www.ietf.org/rfc/rfc0821.txt]. This applicationprotocols is used to send email over the Internet. A few years back, I wrotetwo 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 dothe same programming in Microsoft's new C# language.
The dotNET frameworkalready contains an SMTP class in the System.Web.Mailnamespace called SmtpMail. This class is sufficientfor sending email over the Internet and I would not suggest that the class I'mpresenting in this article is any better or worse. Let's just say that it isdifferent. If you can get away with using the dotNET SmtpMail class, then I suggest you do just that. The onlyadvantage of my class is that it is open source and let me suggest that the SmtpMail class in dotNET has afew more features.
My motivation in writing this article isnot to try and write a better SMTP class, but rather to show how to writeTCP/IP based clients in C#. And here goes.
I started by writing a custom exceptionfor my C# Smtp class. Whenever my C# class encountersfaults, I'll throw an instance of this exception. The exception class ispresented 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 basefunctionality that is required to do TCP/IP programming. Our class declarationis presented in Listing 2.
Listing Error! Bookmark not defined.: ClassDeclaration
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 ofthe email. The subject data member is the subject of the email. Either bodyText or bodyHtml willrepresent the body of the email. The server data member represents the SMTPserver where our client is sending the message. The data member definitions arepresented in Listing 3.
Listing Error! Bookmark not defined.: DataMembers
public class Smtp : System.Net.Sockets.TcpClient
{
public string from = null;
public ArrayList to;
public ArrayList cc;
public ArrayList bcc;
an>
n> public string subject = null; public string bodyText = null; public string bodyHtml = null; public string server = null; The to, cc and bcc data members arearrays, in order to allow multiple recipients of all three types. All threearrays must be created in the constructor of our class. The constructor of ourclass 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 ourclass. Once you've set the subject, body, from and recipient data members, yousimply 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 tostep 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.: SendMethod 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") { < /span> 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());
}
ass="smallblack">}
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, theConnect, Write and Response methods. The Connect method is inherited from the TcpClient class and establishes a TCP connection betweenour client and a TCP server. The other two methods are implemented in our classand described in the next paragraphs.
The Write method writes data to thesocket. The Write method is presented in Listing 6.
Listing Error! Bookmark not defined.: WriteMethod
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 ASCIIcharacters, but rather is based on Unicode. Thus in order to send message
s onSMTP we must first convert the string input parameter to an array of ASCIIbytes. We use the ASCIIEncoding class in dotNET to make this transformation. Then we retrieve thesocket stream using the GetStream method inheritedfrom the TcpClient class and write the bytes to thestream.
The Response method receives data fromthe socket. The Response method is presented in Listing 7.
Listing Error! Bookmark not defined.: ResponseMethod
public string Response()
{
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
byte []serverbuff = newByte[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 retrievingthe bytes from the stream and then converts the incoming ASCII bytes to ournative C# string type.
Now that we have an SMTP class, you mightbe wondering how you use it. To send an SMTP message, you simply instantiate aninstance of the class, set the appropriate data members and call the Sendmethod.
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 validvalues. A valid from address may be "randy@kbcafe.com (Randy CharlesMorin)". Please don'
;t use this address, I get enough emails already.
About the Author
Randy Charles Morin is the ChiefArchitect of SportMarkets Development from Toronto,Canada and lives with his wife, Bernadette and two kids, Adelaineand Brayden in Brampton, Canada. He is the author ofthe KBCafe.com website [http://www.kbcafe.com], many programming books and manyarticles.












No comments yet... Be the first to leave a reply!