Click here to Skip to main content
15,885,244 members
Articles / Programming Languages / Visual Basic
Article

POP3 Client as a C# Class

Rate me:
Please Sign up or sign in to vote.
4.89/5 (31 votes)
5 Aug 20035 min read 393.9K   10.4K   160   56
An article description of a C# class that implements the standard POP3 commands.

Sample Image - pop3client.gif

Introduction

After reading Agus Kurniawan's article on using C# to communicate with a POP3 server I decided that I'd get a lot more milage if I built up a class that would act as a POP3 client. I decided to implement methods for each of the standard POP3 commands, with each method returning a string containing the response of the POP3 server (where appropriate.) In some situations the command is not valid so the methods detect this and returns an error message rather then sending the command to the server. The source code accompanying this article contains the class definitions and the demo console application (shown above) shows how to use the class to retrieve from a POP3 mail server.

Classes, Methods and Properties

The attached source code contains one class: POP3Client

The class POP3Client contains ten public methods, nine of which represent the nine standard POP3 commands:

  • DELE,
  • LIST,
  • NOOP,
  • PASS,
  • QUIT,
  • RETR,
  • RSET,
  • STAT
  • and USER

  • Each of these "POPmethods" returns a string containing either the response of the POP3 server or an error message if the command was issues inappropriately. The final public method: connect is used to initialize the connection. The optional POP3 commands: APOP, TOP and UIDL are not implemented.

    Soon after I started working on this I realized that all the POP3methods could be implemented with the same 4 basic steps:

    1. See if the command was valid in the current POP state.
    2. If so, send the command to the server.
    3. Read back the response.
    4. Change POP State (if needed).

    I decided to keep track of the current state of the POP session with a property named state with I declared to be of the enumerated type connect_state. You can see these declarations near the top of the class definition.
    public enum connect_state {disc,AUTHORIZATION,TRANSACTION,UPDATE};
    
    ...
    
    public connect_state state=connect_state.disc ;

    There are three POP states:AUTHORIZATION,TRANSACTION,UPDATE. (For a complete definition of the POP3 protocol see RFC 1725 .) The property state is set to disconnected before any connection to the POP3 server is established, at which time it enters AUTHORIZATION.


    I also thought it would be useful to store the user name, password, pop server name and error state (i.e.: did an error occur on the last POP3 command), so I add these properties to the class:

    public string user;
    public string pwd;
    public string pop;
    public bool error;
    The mechanisms for connecting to the server (a TcpClient) and sending (a NetworkStream) and receiving (a StreamReader) data I grabbed straight from Agus's code. I even kept the same variable names:
    //borrowed from Agus Kurniawan's article:"Retrieve Mail From 
    // a POP3 Server Using C#"  at http://www.codeproject.com/csharp/popapp.asp 
    private TcpClient Server;
    private NetworkStream NetStrm;
    private StreamReader  RdStrm;
    private string Data;
    private byte[] szData;
    private string CRLF = "\r\n";    

    Before we can do anything else we need to establish the connection to the server and get things flowing in the network streams. The is done by calling the public method connect.

    public string connect()
    {
        //Initialize the connection.  This code snipped "borrowed"
        //with some modifications...
        //from the article "Retrieve Mail From a POP3 Server Using C#" at
        //www.codeproject.com by Agus Kurniawan
        //http://www.codeproject.com/csharp/popapp.asp
    
        // create server with port 110
        Server = new TcpClient(pop,110);                                
            
        try
        {
            // initialization
            NetStrm = Server.GetStream();
            RdStrm= new StreamReader(Server.GetStream());
    
            //The pop session is now in the AUTHORIZATION state
            state=connect_state.AUTHORIZATION ;
            return(RdStrm.ReadLine ());
        }            
        catch(InvalidOperationException err)
        {
            return("Error: "+err.ToString());
        }
    
    }

    Notice that as soon as the connection is initialized, the session enters the AUTHORIZATION state


    As mentioned earlier, each of the nine POP3methods have essentially the same structure. The source code for the DELE method shows this structure:

    public string DELE(int msg_number)
    {
        string temp;
            
        if (state != connect_state.TRANSACTION )
        {
            //DELE is only valid when the pop session is in the TRANSACTION STATE
            temp="Connection state not = TRANSACTION";
        }
        else
        {
            issue_command("DELE " + msg_number.ToString ());
            temp=read_single_line_response();            
        }
        return(temp);
    }

    First off, we know that the DELE POP3 command is only valid in the TRANSACTION state, so if the class is not in that state, as recorded in the property state, then the DELE method returns a error message rather then sending the request to the POP3 server. It won't hurt the POP3 server to send it a DELE when is it in another state, it will just generate it's own error message. If you would rather deal with the POP3 server's error messages about the state, just remove the ifstructure and just leave the issue_command() call. Once we have established that the POP session is in the correct state, we send the "DELE" command to the server using the private method issue_command. RFC 1725 states the DELE command returns a single line response from the POP3 server, which we read with the read_single_line_response method. Both methods are pretty straight forward, either writing characters to or reading them from the network streams connect established with the server. Since the POP session is still in the TRANSACTION state after the DELE command, we do not need to worry about changing state. See the source code for the PASS method for an example of state change.

    C#
    private void issue_command(string command)
    {
        //send the command to the pop server.  This code snipped "borrowed"
        //with some modifications...
        //from the article "Retrieve Mail From a POP3 Server Using C#" at
        //www.codeproject.com by Agus Kurniawan
        //http://www.codeproject.com/csharp/popapp.asp
        Data= command + CRLF;
        szData = System.Text.Encoding.ASCII.GetBytes(Data.ToCharArray());
        NetStrm.Write(szData,0,szData.Length);
    
    }
    private string read_single_line_response()
    {
        //read the response of the pop server.  This code snipped "borrowed"
        //with some modifications...
        //from the article "Retrieve Mail From a POP3 Server Using C#" at
        //www.codeproject.com by Agus Kurniawan
        //http://www.codeproject.com/csharp/popapp.asp
        string temp;
        try
        {
            temp = RdStrm.ReadLine();
            was_pop_error(temp);                
            return(temp);
        }
        catch(InvalidOperationException err)
        {
            return("Error in read_single_line_response(): " + err.ToString ()) ;
        }
    
    }

    Note, in some cases, some POP3 commands return multi-line responses. To handle these there is also a method named read_multi_line_response. I mentioned above that I think it will be useful to know explicitly if the last POP command executes successfully or if the the POP3 server returned an error. This is checked by the private method was_pop_error.

    C#
    private void was_pop_error(string response)
    {
        //detect if the pop server that issued the response believes that
        //an error has occured.
    
        if(response.StartsWith ("-"))
        {
            //if the first character of the response is "-" then the 
            //pop server has encountered an error executing the last 
            //command send by the client
            error=true;
        }
        else
        {
            //success
            error=false;
        }
    }

    Usage Examples

    The details of the POP3 protocol are a little beyond the scope of this article. So if you would like to learn more about POP3, I'll just refer you to RFC 1725, which you can find here. Let's look briefly at the demo application to see how the class is used:

    C#
    static void Main(string[] args)
    {
                
        POP3Client.POP3client  Demo = new POP3Client.POP3client();
        Console.WriteLine ("****connecting to server:");
        Console.WriteLine (Demo.connect ("your_pop3_server"));
        Console.WriteLine ("****Issuing USER");
        Console.WriteLine (Demo.USER ("user_id"));
        Console.WriteLine ("****Issuing PASS");
        Console.WriteLine (Demo.PASS ("password"));
        Console.WriteLine ("****Issuing STAT");
        Console.WriteLine (Demo.STAT () );
        Console.WriteLine ("****Issuing LIST");
        Console.WriteLine (Demo.LIST () );
        Console.WriteLine ("****Issuing RETR 700...this" + 
                           " will cause the POP3 server to gack a "
                           + "hairball since there is no message 700");  
        Console.WriteLine (Demo.RETR (700) );
        // this will cause the pop3 server to throw 
        // an error since there is no message 700
    
        Console.WriteLine ("****Issuing RETR 7");
        Console.WriteLine (Demo.RETR (7) );
        Console.WriteLine ("****Issuing QUIT");
        Console.WriteLine (Demo.QUIT ());
    
        Console.ReadLine ();
    }

    In general, you create an instance of the POP3Client class, invoke the connect method with the name of your POP3 server and start issuing commands. You will need to successfully logon to the server by invoking the USER and PASS methods, in that order, with valid login information before you can invoke the other POP3methods.

    I hope some of you find this useful. I'd love some feedback / comments.

    Please be aware that this code come with no warranty of any sort, express or implied. It is provided strictly "as is" and is indended solely for educational purposes. YOU USE IT AT YOUR OWN RISK. By using this code you agree to hold the Author and Restek blameless for any loss resulting from the use of the code.

    History

    • 6 Aug 2003 - Ronny Reinertsen kindly ported the C# version to VB.NET

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here


    Written By
    Web Developer
    United States United States
    I completed a B.S. in Computer Science at Rensselaer Poly Tech in 1995. Then I did a Ph.D. in Kinesiology at Penn State (2001), applying nonlinear dynamics and complexity theory to the study of human coordination. I am currently employed by Restek Corporation (www.restekcorp.com) in Bellefonte, PA where I develop data-driven web-applications with ASP, ASP.NET and SQL.

    Comments and Discussions

     
    Questionretr Pin
    Ambrus Weisz18-Jan-12 7:57
    Ambrus Weisz18-Jan-12 7:57 
    Questionproblem in code Pin
    triptisonkar16-Aug-11 22:18
    triptisonkar16-Aug-11 22:18 
    QuestionHow to Read folder lik "junk" or any customized folder on mailserver? Pin
    jymitra19-Jul-10 21:43
    jymitra19-Jul-10 21:43 
    AnswerRe: How to Read folder lik "junk" or any customized folder on mailserver? Pin
    kirnyk25-Apr-11 4:34
    kirnyk25-Apr-11 4:34 
    GeneralPOP3 component on http://intsolsoftware.com/products/index.php Pin
    tom-c@wp.pl25-Nov-09 21:07
    tom-c@wp.pl25-Nov-09 21:07 
    Generalemail application Pin
    deep769-Jun-09 2:23
    deep769-Jun-09 2:23 
    GeneralAccessing the methods Pin
    Member 45528217-Jun-09 17:51
    Member 45528217-Jun-09 17:51 
    GeneralRe: Accessing the methods Pin
    Kishore K V S S30-Oct-09 9:16
    Kishore K V S S30-Oct-09 9:16 
    GeneralUse Exchange to send and receive email Pin
    gosoriob13-Oct-08 11:07
    gosoriob13-Oct-08 11:07 
    Generalencoding problems Pin
    GeorgeBerry7-Aug-08 0:19
    GeorgeBerry7-Aug-08 0:19 
    Generalneed help understanding part of your code Pin
    Stephen Po17-Jun-08 9:00
    Stephen Po17-Jun-08 9:00 
    GeneralRe: need help understanding part of your code Pin
    yetibrain25-Aug-08 9:44
    yetibrain25-Aug-08 9:44 
    Generalpop3 password from registry Pin
    Naresh Jakher3-Jan-08 23:25
    Naresh Jakher3-Jan-08 23:25 
    GeneralCompatibility with .NET 2.0 Pin
    onstottj28-Oct-07 6:51
    onstottj28-Oct-07 6:51 
    QuestionNeed Help Pin
    kanzz2-Aug-07 19:45
    kanzz2-Aug-07 19:45 
    GeneralError in connection Pin
    Deepak garg24819-Apr-07 0:30
    Deepak garg24819-Apr-07 0:30 
    QuestionDelayed response Pin
    AndyCLon25-May-06 9:59
    AndyCLon25-May-06 9:59 
    GeneralMail Size Pin
    minyakcapkapak6-Mar-06 23:05
    minyakcapkapak6-Mar-06 23:05 
    GeneralRe: Mail Size Pin
    AndyCLon25-May-06 9:57
    AndyCLon25-May-06 9:57 
    GeneralDestroying object Pin
    dr.TyGER (Konstantin)21-Feb-06 23:40
    dr.TyGER (Konstantin)21-Feb-06 23:40 
    GeneralDoes not work as Windows Service Pin
    Anonymous1-Oct-05 22:43
    Anonymous1-Oct-05 22:43 
    GeneralRe: Does not work as Windows Service Pin
    Deem22-Mar-06 1:06
    Deem22-Mar-06 1:06 
    GeneralI coudnt get Body Of Html Format Pin
    nazli12-Mar-05 4:20
    nazli12-Mar-05 4:20 
    GeneralRe: I coudnt get Body Of Html Format Pin
    Svenrutten14-Jun-05 21:35
    Svenrutten14-Jun-05 21:35 
    GeneralRe: I coudnt get Body Of Html Format Pin
    nazli17-Jun-05 18:35
    nazli17-Jun-05 18:35 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.