Click here to Skip to main content
15,889,992 members
Articles / Programming Languages / C#
Article

A POP3 Client in C# .NET

Rate me:
Please Sign up or sign in to vote.
4.80/5 (163 votes)
9 Feb 2004CPOL4 min read 1.8M   55.3K   334   392
A POP3 client in C# .NET for reading and processing emails (including attachments).

Introduction

I was asked some time ago to develop software which involved extracting bodies and subject lines from emails. "Humm ...", I thought, "connect to mail server on 110, send POP3 commands, receive data, sorted!". Indeed, at my first attempt it was a piece of cake: reading emails - no problem. Colleagues working at my company were evangelizing about what we could do: "Yeah mate, we can automatically process emails, no sweat".

Clients would then ask more questions: "can we send it in rich text or HTML?". "Yeah, sure we can!!". "What about processing them automatically?". "Hey - you're talking to the email kings!!". "What about processing multiple attachments, WAV's MP3's JPEG's?". "Ermmm ... can I get back to you on that ...". Wasn't as easy as I'd thought ...

The reason why I found it quite difficult to code initially was mainly due to how MIME is written and how extremely ugly it can look at first glance. Here's a sample, which contains two multipart blocks (I'll explain this later):

Received: by Mailserver
        id <A href="mailto:01C3EFF7.990BBDF0@TEST">01C3EFF7.990BBDF0@TEST</A>; Tue, 11 Feb 2003 17:02:00 -0000
Message-ID: <A href="mailto:2CB86919E23ED51191840060080C3DAE02320B76@MAILSERVER">2CB86919E23ED51191840060080C3DAE02320B76@MAILSERVER</A>
From: Desmond McCarter
To: testemail
Subject: FW: my subject
Date: Tue, 11 May 2003 17:01:59 -0000
MIME-Version: 1.0
Content-Type: multipart/mixed;
        boundary="----_=_NextPart_000_01C3EFF7.990BD65A"
This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.

------_=_NextPart_000_01C3EFF7.990BD65A
Content-Type: text/plain;
        charset="iso-8859-1"
        
        
        
-----Original Message-----
From: Lisa Cleary [mailto:lisa@cleary.com]
Sent: 11 May 2003 16:17
To: 'Desmond McCarter'
Subject: RE: Test

------_=_NextPart_000_01C3EFF7.990BD65A
Content-Type: application/vnd.ms-excel;
        name="test.xls"
Content-Transfer-Encoding: base64
0M8R4KGxGuEAAAAAAAAAAAAAAAAAAAAAPgADAP7/CQAGAAAAAAAAAAAAAAAEAAAAwQEAAAAAAAAA
EAAA/v///wAAAAD+////AAAAAL0BAAC+AQAAvwEAAMABAAD/////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////8J
CBAAAAYFAP4czQfJQAAABgEAAOEAAgCwBMEAAgAAAOIAAABcAHAADQAAV0ggU21pdGggTmV3cyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEIAAgCwBGEBAgAAAMABAAA9AQQA
AQD8AJwAAgAOABkAAgAAABIAAgAAABMAAgAAAK8BAgAAALwBAgAAAD0AEgAXB6b/WC+gIzgAAQAA
AAEAWAJAAAIAAACNAAIAAAAiAAIAAAAOAAIAAQC3AQIAAADaAAIAAAAxABoAyAAAAP9/kAEAAAAA
.

MIME (Multipurpose Internet Mail Extensions): A quick and dirty guide

Data that is transferred over the Internet is sent as a collection of bytes (i.e. a collection of 8 bits). This information includes text files, CSVs or even JPEGs or movies. "Hey" you might say "you can't send binary data as a collection of bytes!". Yes you can, with a suitable encoding scheme: using the base 64 algorithm for example (check out the System.Convert.ToBase64String method in your .NET framework). This information (we're talking in email context) also includes the subject, body and forwarded items. For the client (sending the email) and the server (reading the email) should understand each other and, in order to do that, they must conform (send and receive data) in MIME format.

In the snipped MIME example (above), you can see and easily understand the basic fields:

"From:" - who sent the email, "To:" - who is receiving the email, "Subject:" - the subject of the email and "Date:" - the date/time the email was sent.

The "Content-Type:" determines what type of content the email contains. In a simple text email (i.e. with no attachments) this is normally "text/plain". You can see however (I hope you can anyway) that this email actually contains an attachment: test.xls. Emails that contain attachments have a MIME content type of "multipart/mixed". This means that the email contains data sectioned into multiple parts: the body and attachments (or in this case "attachment") etc. The boundary (boundary="----_=_NextPart_000_01C3EFF7.990BD65A") identifies where these parts start and stop. The body in my example (and in most emails) is the first part of this multipart email. The start of the body identified at the first boundary declaration:

------_=_NextPart_000_01C3EFF7.990BD65A
Content-Type: text/plain;
        charset="iso-8859-1"




-----Original Message-----
From: Lisa Cleary [mailto:lisa@cleary.com]
Sent: 11 May 2003 16:17
To: 'Desmond McCarter'
Subject: RE: Test

You can also see from the above MIME text that this part also contains its content type, i.e. the format of the body: text/plain. All parts of a multipart email have their header definitions first, then an empty line, then the actual body.

The next part of this multipart email is the attachment:

------_=_NextPart_000_01C3EFF7.990BD65A
Content-Type: application/vnd.ms-excel;
        name="test.xls"
Content-Transfer-Encoding: base64

0M8R4KGxGuEAAAAAAAAAAAAAAAAAAAAAPgADAP7/CQAGAAAAAAAAAAAAAAAEAAAAwQEAAAAAAAAA
EAAA/v///wAAAAD+////AAAAAL0BAAC+AQAAvwEAAMABAAD/////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////8J
CBAAAAYFAP4czQfJQAAABgEAAOEAAgCwBMEAAgAAAOIAAABcAHAADQAAV0ggU21pdGggTmV3cyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEIAAgCwBGEBAgAAAMABAAA9AQQA
AQD8AJwAAgAOABkAAgAAABIAAgAAABMAAgAAAK8BAgAAALwBAgAAAD0AEgAXB6b/WC+gIzgAAQAA
AAEAWAJAAAIAAACNAAIAAAAiAAIAAAAOAAIAAQC3AQIAAADaAAIAAAAxABoAyAAAAP9/kAEAAAAA
.

Note again, the second and final "multipart part" (i.e. the attachment) start off with the boundary declaration. Also note that the content type is defined, as well as the name and encoding scheme used to convert the attachment, enabling it to be sent over the internet in byte format. You need to take note that had this email had another attachment, then the second attachment (the third "multipart part") would start off with the same boundary declaration and so on.

MIME is in fact object oriented

The first mistake I made when building a POP3 library was to develop it in a language that was unsuitable: C. It took too long to write and did indeed get very dirty. It took about 3 weeks to develop and test my library, whereas in C# it took a day and a half!! The reason for this is that MIME, you can say, is an object oriented format: each part of a multipart email (even the body of a simple text/plain mail + main headers etc.) can be thought of as being objects. This is one of the main reasons why I wrote it in C# (could have used Java or even J2EE but ...).

Code

The code I have written starts off with a class called Pop3Client. This class is used to instantiate connection to a POP3 server:

C#
Pop3Client email = new Pop3Client("user", "password", "mail.server.com");

You then open the Inbox as follows:

C#
email.OpenInbox();

To go to the first email, then you call the NextEmail() method, which returns true if there is a "next email" or false if no such email exists. There is also a IsMultipart singleton, which you can use to check and see whether the email has multiple parts (i.e. attachments). Here's an example of how the code might look:

C#
try {
    Pop3Client email = new Pop3Client("user", "password", "mail.server.com");
    email.OpenInbox();

    while( email.NextEmail())

    {
        if(email.IsMultipart)
        {
            IEnumerator enumerator = email.MultipartEnumerator;
            while(enumerator.MoveNext())
            {
                Pop3Component multipart = (Pop3Component)
                enumerator.Current;
                if( multipart.IsBody )
                {
                    Console.WriteLine("Multipart body:"+
                    multipart.Body);
                }
                else
                {
                    Console.WriteLine("Attachment name="+
                    multipart.Name); // ... etc
                }
            }
        }
    }

    email.CloseConnection();

}
catch(Pop3LoginException)
{
    Console.WriteLine("You seem to have a problem logging in!");
}

I have also implemented other functionalities within this class library which includes saving attachments (currently done automatically) in their original format, a getter for the filename, extension etc.

Have a look and see what you think: I definitely found it fun to write and explore!!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United Kingdom United Kingdom
Des is a Technical Architect working for a private telecoms based company in the United Kingdom. He has been involved in programming for over 14 years and has worked on many platforms including UNIX, Linux and Windows.

Language specialities are C, C++, C#.NET, Java & J2EE and shell scripting (especially on UNIX/Linux). Also enjoys writing and optimising SQL scripts.

Des is engaged to a lovely girl called Lisa!

Comments and Discussions

 
GeneralRe: My vote of 5 Pin
Member 788269815-Mar-12 10:52
Member 788269815-Mar-12 10:52 
QuestionFilename and Name - trying to save attachments Pin
benbawden13-Sep-10 6:55
benbawden13-Sep-10 6:55 
AnswerRe: Filename and Name - trying to save attachments Pin
John LAWDeed16-Mar-11 2:59
John LAWDeed16-Mar-11 2:59 
GeneralAccess to "Date" or any other unique reference Pin
David Cresswell11-Aug-10 6:54
David Cresswell11-Aug-10 6:54 
GeneralMy vote of 5 Pin
biswajitcb29-Jul-10 3:22
biswajitcb29-Jul-10 3:22 
GeneralMethod email.NextEmail() doesn't work Pin
Paulo Roussenq6-May-10 9:54
Paulo Roussenq6-May-10 9:54 
Generalattachment is not saving if mail is comming from gmail Pin
gulam_last2-May-10 21:24
gulam_last2-May-10 21:24 
GeneralUpdated Code Pin
Christopher Stratmann16-Apr-10 8:41
Christopher Stratmann16-Apr-10 8:41 
For all those people who find this code to be very useful, but find that the code has been written an "oldish" style. I have some updated code below. Not all the code has been updated but for the most part it is now readable. If you have any updates please comment me...

Below is my new Pop3Client.cs
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

namespace Email
{
    /// <summary>
    /// A client that allows for connecting to an email accounts using POP3.
    /// </summary>
    /// <seealso href="http://www.codeproject.com/KB/IP/despop3client.aspx"/>
    public class Pop3Client : IDisposable
    {
        #region Fields

        /// <summary>
        /// Contains the manual reset event that will assist in waiting for an entire email to be
        /// received.
        /// </summary>
        private readonly ManualResetEvent _resetEvent = new ManualResetEvent(false);

        /// <summary>
        /// Contains the email address of the email account that will be opened within the <see cref="_server"/>.
        /// </summary>
        private string _email;

        /// <summary>
        /// Contains the password for the <see cref="_email"/> that will be opened within the <see cref="_server"/>.
        /// </summary>
        private string _emailPassword;

        /// <summary>
        /// Contains the name of the server that contains the <see cref="Email"/> that will be opened.
        /// </summary>
        private string _server;

        #endregion
        #region Properties

        /// <summary>
        /// Gets or sets the email address of the email account that will be opened within the <see cref="Server"/>.
        /// </summary>
        public string Email
        {
            get
            {
                if (_email == null)
                {
                    _email = string.Empty;
                }
                return _email;
            }
            set
            {
                _email = value;
            }
        }

        /// <summary>
        /// Gets or sets the password for the <see cref="Email"/> that will be opened within the <see cref="Server"/>.
        /// </summary>
        public string EmailPassword
        {
            get
            {
                if (_emailPassword == null)
                {
                    _emailPassword = string.Empty;
                }
                return _emailPassword;
            }
            set
            {
                _emailPassword = value;
            }
        }

        /// <summary>
        /// Gets the manual reset event that will assist in waiting for an entire email to be
        /// received.
        /// </summary>
        protected ManualResetEvent ResetEvent
        {
            get { return _resetEvent;  }
        }

        /// <summary>
        /// Gets or sets the name of the server that contains the <see cref="Email"/> that will be opened.
        /// </summary>
        public string Server
        {
            get
            {
                if (_server == null)
                {
                    _server = string.Empty;
                }
                return _server;
            }
            set
            {
                _server = value;
            }
        }

        /// <summary>
        /// Gets or sets the socket that will contain the connection to the server.
        /// </summary>
        protected Socket ServerSocket { set; get; }

        #endregion
        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Pop3Client"/> class.
        /// </summary>
        public Pop3Client()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Pop3Client"/> class with setting the
        /// <paramref name="email"/>, <paramref name="emailPassword"/>, and <paramref name="server"/>.
        /// </summary>
        /// <param name="email">The email address of the email account that will be opened within the <paramref name="server"/>.</param>
        /// <param name="emailPassword">The password for the <paramref name="email"/> that will be opened within the <paramref name="server"/>.</param>
        /// <param name="server">The name of the server that contains the <paramref name="server"/> that will be opened.</param>
        public Pop3Client(string email, string emailPassword, string server)
        {
            _email = email;
            _emailPassword = emailPassword;
            _server = server;
        }

        #endregion
        #region Methods

        /// <summary>
        /// Deletes the messages within the <see cref="Email"/> account.
        /// </summary>
        /// <param name="message">The message to be deleted.</param>
        /// <exception cref="ArgumentNullException">Thrown if the parameter <paramref name="message"/> is <c>null</c>.</exception>
        /// <remarks>
        /// After calling this function the email message will not be deleted but marked for
        /// deletion.  After this object is <see cref="Dispose"/>, then the email will be 
        /// successfully deleted.
        /// </remarks>
        /// <returns><c>true</c> is returned if the message is successfully marked for deletion; otherwise, <c>false</c>.</returns>
        public bool DeleteMessage(Pop3Message message)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }
            return DeleteMessageAt(message.InboxPosition);
        }

        /// <summary>
        /// Deletes a message at a given position within the <see cref="Email"/> account.
        /// </summary>
        /// <param name="messagePosition">The position of the message that is to be deleted within the <see cref="Email"/> account.</param>
        /// <remarks>
        /// After calling this function the email message at the specified position will not be deleted but marked
        /// for deletion.  After this object is <see cref="Dispose"/>, then the email will be successfully 
        /// deleted.
        /// </remarks>
        /// <returns><c>true</c> is returned if the message is successfully marked for deletion; otherwise, <c>false</c>.</returns>
        public bool DeleteMessageAt(long messagePosition)
        {
            // If the server socket is null then open the email to be read.
            if (ServerSocket == null)
            {
                OpenEmail();
            }

            SendData("dele " + messagePosition);
            var returned = ReadData();
            return Regex.Match(returned, @"^.*\+OK.*$").Success;
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            SendData("quit");
            ServerSocket = null;
        }

        /// <summary>
        /// Returns a total email count without receiving a collection of all the email from the 
        /// <see cref="Email"/> account.
        /// </summary>
        /// <exception cref="Pop3ReceiveException">Thrown if there is a problem converting the POP3 response into a valid email count.</exception>
        /// <returns>The number of email messages within the <see cref="Email"/> account are returned.</returns>
        public long GetEmailMessageCount()
        {
            // If the server socket is null then open the email to be read.
            if (ServerSocket == null)
            {
                OpenEmail();
            }

            SendData("stat");
            var returned = ReadData();

            // Contains the expression to be used when extracting the email count.
            const string expression = @"^.*\+OK[ |	]+([0-9]+)[ |	]+.*$";

            if (Regex.Match(returned, expression).Success)
            {
                long count;
                if (!long.TryParse(Regex.Replace(returned.Replace("\r\n", string.Empty), expression, "$1"), out count))
                {
                    throw new Pop3ReceiveException("The response from the POP3 connection could not be converted into a valid email count: " + returned);
                }
                return count;
            }

            return 0;
        }

        /// <summary>
        /// Returns a collection of all the emails within the specified <see cref="Email"/> account.
        /// </summary>
        /// <exception cref="Pop3MessageException">Thrown if there is a problem creating the collection of messages found in the <see cref="Email"/> account.</exception>
        /// <returns>A collection of all the emails will be returned that are within the email account.</returns>
        public Pop3MessageCollection GetEmailMessages()
        {
            // If the server socket is null then open the email to be read.
            if (ServerSocket == null)
            {
                OpenEmail();
            }

            // Create the collection of messages to be returned.
            var messages = new Pop3MessageCollection();

            // Start reading the messages at the first position.
            var position = 1;

            SendData("list " + position);
            var returned = ReadData();
            while (returned.Length >= 4 && string.CompareOrdinal(returned.Substring(0, 4), "-ERR") != 0)
            {
                messages.Add(GetEmailMessage(position));

                // Increase the position to read the next email message.
                position++;

                // Read the next email message.
                SendData("list " + position);
                returned = ReadData();
            }

            return messages;
        }

        /// <summary>
        /// Initializes the <see cref="ServerSocket"/> of the <see cref="Email"/> account.
        /// </summary>
        /// <exception cref="Pop3ConnectException">Thrown if there is the <see cref="Server"/> is <see cref="string.Empty"/> or <c>null</c>.</exception>
        /// <exception cref="Pop3ConnectException">Thrown if there is a problem connecting to the <see cref="Server"/>.</exception>
        protected void InitializeSocket()
        {
            try
            {
                // Get host related information.
                var hostEntry = Dns.GetHostEntry(Server);

                // Loop through the AddressList to obtain the supported 
                // AddressFamily. This is to avoid an exception that 
                // occurs when the host IP Address is not compatible 
                // with the address family 
                // (typical in the IPv6 case).

                foreach (var address in hostEntry.AddressList)
                {
                    var ipe = new IPEndPoint(address, 110);
                    var socket = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                    socket.Connect(ipe);

                    if (socket.Connected)
                    {
                        // we have a connection and return this socket...
                        ServerSocket = socket;
                        return;
                    }
                }
            }
            catch (Exception ex)
            {
                // Wrap the connection as a Pop3ConnectionException...
                throw new Pop3ConnectException(ex.ToString(), ex);
            }

            // Since a connection could not be made throw an exception.
            throw new Pop3ConnectException("Error connecting to " + Server);
        }

        /// <summary>
        /// Returns the email message at the specified position within the <see cref="Email"/> account.
        /// </summary>
        /// <param name="position">The position of the email within the <see cref="Email"/> account to read the email.</param>
        /// <returns>The email message that was constructed.</returns>
        protected Pop3Message GetEmailMessage(int position)
        {
            var message = new Pop3Message
                              {
                                  InboxPosition = position
                              };

            // Tell the POP3 Server we want to start reading
            // email from inbox...
            SendData("retr " + message.InboxPosition);
            
            var state = new Pop3StateObject
                            {
                                Buffer = new byte[256],
                                WorkSocket = ServerSocket
                            };

            // This ensures that every time an email is read that it will wait until the "Set" method
            // is called.
            ResetEvent.Reset();

            // Read all the data returned from the email.
            ServerSocket.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, new AsyncCallback(ReceiveCallback), state);

            // wait until no more data to be read ...
            ResetEvent.WaitOne();

            var returned = state.Data;

            // Parse all the lines within the email.
            var lines = returned.Split(new[] { '\r' });

            var bodyStart = 0;
            var multipartBoundary = string.Empty;
            for (var i = 0; i < lines.Length; i++)
            {
                var currentLine = lines[i].Replace("\n", string.Empty);

                if (string.IsNullOrEmpty(currentLine))
                {
                    bodyStart = i + 1;
                    break;
                }

                if (Regex.Match(currentLine, "^From:.*$").Success)
                {
                    message.From = Pop3Parse.From(currentLine);
                    continue;
                }

                if (Regex.Match(currentLine, "^To:.*$").Success)
                {
                    message.To = Pop3Parse.To(currentLine);
                    continue;
                }

                if (Regex.Match(currentLine, "^Subject:.*$").Success)
                {
                    message.Subject = Pop3Parse.Subject(currentLine);
                    continue;
                }

                if (Regex.Match(currentLine, "^Content-Type:.*$").Success)
                {
                    message.ContentType = Pop3Parse.ContentType(currentLine).Trim();
                    message.IsMultipart = Pop3Parse.IsMultipart(message.ContentType);
                    if (message.IsMultipart)
                    {
                        if (message.ContentType.EndsWith(";"))
                        {
                            // If the boundary definition is on next line...
                            i++;
                            multipartBoundary = Pop3Parse.MultipartBoundary(lines[i].Replace("\n", string.Empty));
                        }
                        else
                        {
                            // If the boundary definition is on same line as the "Content-Type"...
                            multipartBoundary = Pop3Parse.MultipartBoundary(message.ContentType);
                        }
                    }
                }
            }

            // Gets a collection of all the components to the email.
            var messageComponents = new Pop3MessageComponents(lines, bodyStart, string.IsNullOrEmpty(multipartBoundary) ? null : multipartBoundary, message.ContentType);

            // Check to see the the body exists.
            var multipartEnumerator = messageComponents.ComponentEnumerator;
            while (multipartEnumerator.MoveNext())
            {
                var multipart = (Pop3Component)multipartEnumerator.Current;
                message.Components.Add(multipart);

                if (multipart.IsBody)
                {
                    message.Body = multipart.Data;
                }
            }

            return message;
        }

        /// <summary>
        /// Opens the connection to the email server.
        /// </summary>
        protected void OpenEmail()
        {
            // Before attempting to open the email make sure the Server is not null or empty.
            if (string.IsNullOrEmpty(Server))
            {
                throw new Pop3ConnectException("The server was not specified so a connection could not be made.");
            }

            // Before attempting to open the email make sure the Email is not null or empty.
            if (string.IsNullOrEmpty(Email))
            {
                throw new Pop3ConnectException("The email was not specified so a connection could not be made.");
            }

            // Before attempting to open the email make sure the EmailPassword is not null or empty.
            if (string.IsNullOrEmpty(EmailPassword))
            {
                throw new Pop3ConnectException("The email password was not specified so a connection could not be made.");
            }

            // Get a connection to the server.
            InitializeSocket();

            // Read the socket.
            var returned = ReadData();
            if (returned.Length < 3 || string.CompareOrdinal(returned.Substring(0, 3), "+OK") != 0)
            {
                throw new Pop3ReceiveException("An invalid message was received from the POP3 connection after the initial connection was made: " + returned);
            }

            // Send the UserName of the email account.
            SendData("user " + Email);
            returned = ReadData();
            if (returned.Length < 3 || string.CompareOrdinal(returned.Substring(0, 3), "+OK") != 0)
            {
                throw new Pop3ReceiveException("An invalid message was received from the POP3 connection after submitting the email address: " + returned);
            }

            // Send the Password of the email account.
            SendData("pass " + EmailPassword);
            returned = ReadData();
            if (returned.Length < 3 || string.CompareOrdinal(returned.Substring(0, 3), "+OK") != 0)
            {
                throw new Pop3ReceiveException("An invalid message was received from the POP3 connection after submitting the email and the email password: " + returned);
            }
        }

        /// <summary>
        /// Reads the data from the <see cref="ServerSocket"/> until the end is reached.
        /// </summary>
        /// <exception cref="Pop3ReceiveException">Thrown if the <see cref="ServerSocket"/> is <c>null</c>.</exception>
        /// <exception cref="Pop3ReceiveException">Thrown if there is any problems reading the data from the <see cref="ServerSocket"/>.</exception>
        /// <returns>Returns the string value of the information that is to be read on the <see cref="ServerSocket"/>.</returns>
        /// <seealso href="http://www.yoda.arachsys.com/csharp/readbinary.html" />
        protected string ReadData()
        {
            if (ServerSocket == null)
            {
                throw new Pop3ReceiveException("The POP3 connection to the server socket does not exist and cannot be read.");
            }

            try
            {
                var buffer = new byte[32768];
                using (var ms = new MemoryStream())
                {
                    while (true)
                    {
                        var read = ServerSocket.Receive(buffer, buffer.Length, SocketFlags.None);
                        ms.Write(buffer, 0, read);
                        if (read <= 0 || read < buffer.Length)
                        {
                            buffer = ms.ToArray();
                            return Encoding.ASCII.GetString(buffer, 0, buffer.Length);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Pop3ReceiveException("There was a problem receiving the data from the POP3 connection: " + ex.Message, ex);
            }
        }

        /// <summary>
        /// Receives the callback from an asynchronous call.
        /// </summary>
        /// <param name="ar">The asynchronous result.</param>
        private void ReceiveCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the state object and the client socket 
                // from the asynchronous state object.
                var state = (Pop3StateObject)ar.AsyncState;
                var client = state.WorkSocket;

                // Read data from the remote device.
                var bytesRead = client.EndReceive(ar);
                if (bytesRead > 0)
                {
                    // There might be more data, 
                    // so store the data received so far.
                    state.Data += Encoding.ASCII.GetString(state.Buffer, 0, bytesRead);

                    // Check to see if more data is expected.  A literal "." (or more) followed by
                    // "\r\n" in an email is prefixed with "."...
                    if (!state.Data.EndsWith("\r\n.\r\n"))
                    {
                        ServerSocket.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, new AsyncCallback(ReceiveCallback), state);
                    }
                    else
                    {
                        // Allow the manual reset to stop waiting.
                        ResetEvent.Set();
                    }
                }
            }
            catch (Exception ex)
            {
                // Allow the manual reset to stop waiting.
                ResetEvent.Set();

                throw new Pop3ReceiveException("There was a RecieveCallback error: " + ex, ex);
            }
        }

        /// <summary>
        /// Sends the data throgh the <see cref="ServerSocket"/>.
        /// </summary>
        /// <param name="data">The data that is to be sent through the <see cref="ServerSocket"/>.</param>
        /// <exception cref="Pop3SendException">Thrown if the <see cref="ServerSocket"/> is <c>null</c>.</exception>
        /// <exception cref="Pop3SendException">Thrown if there is any problems sending the data through the <see cref="ServerSocket"/>.</exception>
        protected void SendData(string data)
        {
            if (ServerSocket == null)
            {
                throw new Pop3SendException("The POP3 connection to the server socket does not exist and cannot send any data through it.");
            }

            try
            {
                // Convert the string data to byte data using ASCII encoding.
                var byteData = Encoding.ASCII.GetBytes(data + "\r\n");

                // Begin sending the data to the remote device.
                ServerSocket.Send(byteData);
            }
            catch (Exception ex)
            {
                throw new Pop3SendException("There was a problem sending the data through the POP3 connection: " + ex, ex);
            }
        }

        #endregion
    }
}


Below is my new Pop3Message.cs
using System;

namespace Email
{
    /// <summary>
    /// The actual email message.
    /// </summary>
    [Serializable]
    public class Pop3Message
    {
        #region Fields

        /// <summary>
        /// Contains a collection of all the components within the email message.
        /// </summary>
        private readonly Pop3ComponentCollection _components = new Pop3ComponentCollection();

        /// <summary>
        /// Contains the body of the email message.
        /// </summary>
        private string _body;

        /// <summary>
        /// Contains the content type of the email message.
        /// </summary>
        private string _contentType;

        /// <summary>
        /// Contains the from email address of the email message.
        /// </summary>
        private string _from;

        /// <summary>
        /// Contains the subject of the email message.
        /// </summary>
        private string _subject;

        /// <summary>
        /// Contains the to email address of the email message.
        /// </summary>
        private string _to;

        #endregion
        #region Properties

        /// <summary>
        /// Gets or sets the body of the email message.
        /// </summary>
        public string Body
        {
            get
            {
                if (_body == null)
                {
                    _body = string.Empty;
                }
                return _body;
            }
            set
            {
                _body = value;
            }
        }

        /// <summary>
        /// Gets or sets a collection of all the components within the email message.
        /// </summary>
        public Pop3ComponentCollection Components
        {
            get { return _components; }
        }

        /// <summary>
        /// Gets or sets the content type of the email message.
        /// </summary>
        public string ContentType
        {
            get
            {
                if (_contentType == null)
                {
                    _contentType = string.Empty;
                }
                return _contentType;
            }
            set
            {
                _contentType = value;
            }
        }

        /// <summary>
        /// Gets or sets the from email address of the email message.
        /// </summary>
        public string From
        {
            get
            {
                if (_from == null)
                {
                    _from = string.Empty;
                }
                return _from;
            }
            set
            {
                _from = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether or not the email message contains multiple parts.
        /// </summary>
        public bool IsMultipart { get; set; }

        /// <summary>
        /// Gets or sets the position of the email within the email account.
        /// </summary>
        public long InboxPosition { get; set; }

        /// <summary>
        /// Gets or sets the subject of the email message.
        /// </summary>
        public string Subject
        {
            get
            {
                if (_subject == null)
                {
                    _subject = string.Empty;
                }
                return _subject;
            }
            set
            {
                _subject = value;
            }
        }

        /// <summary>
        /// Gets or sets the to email address of the email message.
        /// </summary>
        public string To
        {
            get
            {
                if (_to == null)
                {
                    _to = string.Empty;
                }
                return _to;
            }
            set
            {
                _to = value;
            }
        }

        #endregion
    }
}


Below is my new Pop3StateObject.cs
using System.Net.Sockets;

namespace Email
{
    /// <summary>
    /// Holds the current state of the client socket.
    /// </summary>
    public class Pop3StateObject
    {
        #region Fields

        /// <summary>
        /// Contains the data for the state object.
        /// </summary>
        private string _data;

        #endregion
        #region Properties

        /// <summary>
        /// Get or sets the buffer that is being used by the state object.
        /// </summary>
        public byte[] Buffer { get; set; }

        /// <summary>
        /// Gets or sets the data for the state object.
        /// </summary>
        public string Data
        {
            get
            {
                if (_data == null)
                {
                    _data = string.Empty;
                }
                return _data;
            }
            set
            {
                _data = value;
            }
        }

        /// <summary>
        /// Gets or sets the worker socket that is currently being used.
        /// </summary>
        public Socket WorkSocket { get; set; }

        #endregion
    }
}


Below is a new class called Pop3ComponentCollection.cs

using System;
using System.Collections.ObjectModel;

namespace Email
{
    /// <summary>
    /// A collection of POP3 components with the email.
    /// </summary>
    [Serializable]
    public class Pop3ComponentCollection : Collection<Pop3Component>
    {
    }
}


Below is a new class called Pop3MessageCollection.cs

using System;
using System.Collections.ObjectModel;

namespace Email
{
    /// <summary>
    /// A collection of email messages.
    /// </summary>
    [Serializable]
    public class Pop3MessageCollection : Collection<Pop3Message>
    {
    }
}

Chris

GeneralRe: Updated Code Pin
testerbddd13-May-10 11:39
testerbddd13-May-10 11:39 
RantThis code needs updating... Pin
Christopher Stratmann16-Apr-10 3:21
Christopher Stratmann16-Apr-10 3:21 
GeneralVery helpfull Pin
Ravi J Patel7-Apr-10 2:09
Ravi J Patel7-Apr-10 2:09 
GeneralMissing multipart boundary Pin
Raios26-Mar-10 6:46
Raios26-Mar-10 6:46 
GeneralNot getting attachment from other mailserver [modified] Pin
NitinMakwana24-Mar-10 3:05
NitinMakwana24-Mar-10 3:05 
Questionhow to run this demo in visual studio 2008? Pin
negozin17-Feb-10 12:45
negozin17-Feb-10 12:45 
AnswerRe: how to run this demo in visual studio 2008? Pin
PrajeeshTest15-Sep-10 3:27
PrajeeshTest15-Sep-10 3:27 
QuestionHow to save complete email in MSG or other format ? Pin
GJR10016-Feb-10 21:47
GJR10016-Feb-10 21:47 
QuestionWrong encoding for german language like Fr=FChester = Frühster (=FC) Pin
TheBigPunisher22-Jan-10 2:07
TheBigPunisher22-Jan-10 2:07 
AnswerRe: Wrong encoding for german language like Fr=FChester = Frühster (=FC) Pin
mich000r9-Mar-10 0:05
mich000r9-Mar-10 0:05 
GeneraliIlegal characters in path Pin
dacku8718-Jan-10 4:24
dacku8718-Jan-10 4:24 
GeneralRe: iIlegal characters in path Pin
kishore.eferns2-Dec-12 22:22
kishore.eferns2-Dec-12 22:22 
Questionhow to save download and save the email attachments Pin
Zapss12-Jan-10 1:12
Zapss12-Jan-10 1:12 
AnswerRe: how to save download and save the email attachments PinPopular
javalace17-Feb-10 18:50
javalace17-Feb-10 18:50 
GeneralRe: how to save download and save the email attachments Pin
Paulo Roussenq6-May-10 11:00
Paulo Roussenq6-May-10 11:00 
GeneralThis code doesn't support format=flowed emails content. Pin
mridey2-Jan-10 19:38
mridey2-Jan-10 19:38 
QuestionNot working, visual studio 2008 problem? Pin
jose.robalo.martins@gmail.com13-Nov-09 1:24
jose.robalo.martins@gmail.com13-Nov-09 1:24 

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.