How To POP3 in C#

This is the second in a series ofarticles on Internet programming with Microsoft's new C# programming language.In the first article, I wrote a simple SMTP class. In this article, I'm going to write a simple POP3 class. The SMTPclass that I wrote was not very useful, except maybe as an exercise, as therealready exists a similar SMTP class in the Web.Mailnamespace of the dot-NET framework called SmtpMail.Our POP3 class in this article will be a little more useful as it doesn'talready exist in the dot-NET framework. I have encountered many POP3 C# classesin my searches of the Internet and most were sufficient to begin programmingemail clients.

I usually begin writing new classes byintroducing an exception class that I can use to throw and catch all exceptionsof the class.

Listing Error! Bookmark not defined.: POP3Exception Class

public class Pop3Exception : System.ApplicationException

{

public Pop3Exception(string str)

:base(str)

{

}

};

I will not explain the exception class,but rather I expect the reader have enough expertise with C# to understand thisexception class before reading the rest of the article.

Next I created a small class that definesa POP3 message.

Listing Error! Bookmark not defined.: POP3Message Class

public class Pop3Message

{

public long number;

public long bytes;

public bool retrieved;

public string message;

};

 

When you retrieve lists of POP3 messagesfrom a POP3 server, the list includes a message number and number of bytes. Youcan then use the message number to retrieve the message content. You'll seethis later when we define our List and Retrieve methods.

We derive our Pop3 class from the System.Net.Sockets.TcpClient class in the dot-NETframework.

Listing Error! Bookmark not defined.: POP3Class Declaration

public class Pop3 : System.Net.Sockets.TcpClient

 <o:p></o:p>

The TcpClientclass and the other classes in the System.Net.Socketsnamespace of the dot-NET framework are great encapsulations of the familiarfunction-oriented socket library.

The first method of our Pop3 class is theConnect method. This method takes a server name, username and passwordparameter to connect to a remote (sometimes local) POP3 server.

Listing Error! Bookmark not defined.: POP3Connect Method

public void Connect(string server, stringusername, string password)

{

string message;

string response;

 

Connect(server, 110);

response = Response();

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

{

throw newPop3Exception(response);

}

 

an lang="EN-US"> message = "USER " + username + "\r\n";

Write(message);

response = Response();

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

{

throw new Pop3Exception(response);

}

 

message = "PASS " + password + "\r\n";

Write(message);

response = Response();

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

{

throw newPop3Exception(response);

}

}

 

We begin by calling the TcpClient.Connect method passing the server name and the110 port. The 110 port number is the well known port number for POP3operations. What that means is that POP3 servers by default should listen forconnections on port 110. When the POP3 server connects to a client, it shouldimmediately respond with the +OK acknowledgement message. Next we send twomessages, USER and PASS, back to the server. The POP3 server should acknowledgea successful login by acknowledging both messages. If the POP3 server returnsanything but +OK, then the message will contain the reason for the failure. Inthe advent of a failure, I attach that failure message to our exception classand throw it back to the client.

It should be noted that some POP3 serversdon't require authentication and may reject the calls to USER and PASS. Ihaven't encountered such a POP3 server, but the protocol allows it. In thosecases, you'll have to slightly modify the class to make things work.

Any use of our Pop3 class should beginwith a call to Connect and end with a class to Disconnect.

Listing Error! Bookmark not defined.: POP3Disconnect Method

public void Disconnect()

{

string message;

string response;

 

message = "QUIT\r\n";

Write(message);

response = Response();

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

{

throw newPop3Exception(response);

}

}

 

The Disconnect method sends a QUITmessage to the POP3 server.

Between the Connect and Disconnect class,the client may call three other methods, List, Retrieve and Delete, any numberof times. The client will usually begin by calling our List method to retrievean array of messages that are queued on the POP3 server.

Listing Error! Bookmark no
t defined.
: POP3List Method

public ArrayList List()

{

string message;

string response;

 

ArrayList retval = new ArrayList();

 

message = "LIST\r\n";

Write(message);

response = Response();

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

{

throw newPop3Exception(response);

}

 

while (true)

{

response =Response();

if (response == ".\r\n")

{

return retval;

}

else<o:p></o:p>

{

Pop3Message msg= new Pop3Message();

char[] seps = { ' ' };

string[] values = response.Split(seps);

msg.number = Int32.Parse(values[0]);

msg.bytes = Int32.Parse(values[1]);

msg.retrieved =false;

retval.Add(msg);

continue;

}

}

}

 

After sending the LIST message to thePOP3 server, the server will respond with a +OK acknowledgement, followed byseveral lines representing one message each and finally by a line with a singleperiod indicating the end of the messages. Each message line has two numbers,the first indicating the unique number of the message and the second indicatingthe message size in bytes.

Our List method will return a list ofPop3Message objects. The objects will only contain the message number and sizeof each message. In order to retrieve the full message, you can pass themessage object to the Retrieve method. The Retrieve method will then respondwith another Pop3Message containing the message content.

Listing Error! Bookmark not defined.: POP3Retrieve Method

public Pop3Message Retrieve(Pop3Message rhs)

{

string message;

string response;

 

Pop3Messagemsg = new Pop3Message();

msg.bytes = rhs.bytes;

msg.number = rhs.number;

 

message = "RETR " + rhs.number+ "\r\n";

Write(message);

response = Response();

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

{

throw newPop3Exception(response);

}

 

msg.retrieved = true;

while (true)

{

response =Response();

if (response == ".\r\n")

{

break;

}

else<o:p></o:p>

{

msg.message +=response;

}

}

 

return msg;

}

 

To retrieve a message from a POP3 server,we send a RETR message with the unique message number. The server then respondswith the +OK acknowledgement, the message content and finally the single periodterminating l
ine.

Retrieving a message does not remove themessage from the POP3 server. A further call to LIST will still return themessage. To remove a message from POP3 server, you have to cal the Deletemethod.

Listing Error! Bookmark not defined.: POP3Delete Method

public void Delete(Pop3Message rhs)

{

string message;

string response;

 

message = "DELE " + rhs.number+ "\r\n";

Write(message);

response = Response();

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

{

throw newPop3Exception(response);

}

}

 

The Delete method sends a DELE messagewith the message number to the POP3 server. The server will respond with the+OK acknowledgment message, if successful.

The List, Retrieve and Delete methods usedtwo private methods, Write and Response, to send and receive messages from thePOP3 server.

Listing Error! Bookmark not defined.: POP3Write Method

private void Write(stringmessage)

{

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

 

byte[] WriteBuffer= new byte[1024];

WriteBuffer = en.GetBytes(message);

 

NetworkStream stream = GetStream();

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

 

Debug.WriteLine("WRITE:" + message);

}

 

C# native strings, like Java nativestrings, are UNICODE. We therefore need to encode and decode the strings to andfrom ASCII. After encoding the string, we can then retrieve the socket streamby calling the TcpClient.GetStream method. I finishthe Write method by called the Debug.Writelinemethod. This sends the string to the debug stream for help with debugging.

Listing Error! Bookmark not defined.: POP3Response Method

private string Response()

{

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

byte []serverbuff = newByte[1024];

NetworkStream stream = GetStream();

int count = 0;

while (true)

{

byte []buff =new Byte[2];

int bytes = stream.Read( buff, 0, 1 );

if (bytes == 1)

{

serverbuff[count]= buff[0];

count++;

 

if (buff[0] =='\n')

{

break;

}

}

else

{

break;

};

};

 

string retval = enc.GetString( serverbuff, 0,count );

Debug.WriteLine("READ:" + retval);

return retval;

}

 

The Response method is similar to theWrite method accept that we retrieve bytes from the stream before decodingthem. Again we call the Debug.WriteLine method tosend the read data to the debug stream and help with debugging.

Note that we have a limitation in theResponse method. We can only retrieve or send up to 1024 bytes at a time. I'llfix this in a later release. If you intend to use this in production, thenyou'll have to do the same first.

Using the new class is pretty easy.

Listing Error! Bookmark not defined.: Usage

static void Main(string[] args)

{

try

{

Pop3 obj = new Pop3();

obj.Connect("mail.xxx.com","yyy", "zzz");

ArrayList list= obj.List();

foreach (Pop3Message msg in list )

{ n>

Pop3Message msg2 = obj.Retrieve(msg);

System.Console.WriteLine("Message{0}: {1}",

msg2.number, msg2.message);

}

obj.Disconnect();

}

catch ( Pop3Exception e )

{

System.Console.WriteLine(e.ToString());

}

catch ( System.Exception e)

{

System.Console.WriteLine(e.ToString());

}

}

 

Instantiate a new object, then call theList method. The List method will return an array of Pop3Message objects. Youcan then iterate through the Pop3Message objects and retrieve each in turn.Finally, you call the Disconnect method to release the socket.

POP3 is described in RFC 1939. You canread the full specification from the IETF website[http://www.ietf.org/rfc/rfc1939.txt?number=1939].

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.

Related Articles :

Twitter Digg Delicious Stumbleupon Technorati Facebook Email

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