Click here to Skip to main content
15,890,717 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

 
Generalemail.Body is encoded Pin
supraracer20-Feb-09 10:33
supraracer20-Feb-09 10:33 
AnswerRe: email.Body is encoded Pin
Gustavo Schuster21-Aug-09 12:33
Gustavo Schuster21-Aug-09 12:33 
GeneralError "throw new Pop3ConnectException(e.ToString());" Pin
huhuhujujuju4-Feb-09 7:13
huhuhujujuju4-Feb-09 7:13 
GeneralRe: Error "throw new Pop3ConnectException(e.ToString());" Pin
crash89316-Jun-09 4:44
crash89316-Jun-09 4:44 
GeneralRe: Error "throw new Pop3ConnectException(e.ToString());" Pin
vivix011-Jun-11 23:27
vivix011-Jun-11 23:27 
GeneralRe: Error "throw new Pop3ConnectException(e.ToString());" Pin
vivix016-Jun-11 22:39
vivix016-Jun-11 22:39 
GeneralRetrieve the original message from a returend mail Pin
Nizze_nilsson17-Dec-08 2:35
Nizze_nilsson17-Dec-08 2:35 
GeneralMy Experience With This Code Pin
jhrees22-Nov-08 15:13
jhrees22-Nov-08 15:13 
I recently downloaded this example and incorporated into an application that automatically adds email to a support tracking system. I thought I would document my experience for the benefit of others who may want to use it.

The code provided a good starting point and I was pleased at how much of a framework it provided. However, if you expect to use it as an out of the box API you may be disappointed. I think it would be very hard to use this code without at least a few hours of modification.

The basic communication to get the raw data via the pop3 protocol worked really well and it did not require any debugging. I spent most of my time working with the parsing to first understand it (I knew nothing about email standards) and to debug why it failed on certain types of messages.

I upgraded the communications with the pop3 server to use streams. This was actually much easier than I thought. Stream APIs share much in common with the socket API used in the original code. By using an SslStream and a RemoteCertificateValidationCallback I was able get it to read from a GMail account.

If you embark on an effort to use this code here are a few things that may help:

The parser makes an assumption there is only one header per line and any subtype is on the next line. For headers like Content-Type and Content-Disposition this is not always true.

For example, in the line below the parser would not recognize the file name.

Content-Disposition: attachment; filename=genome.jpeg;

If you have email messages with multipart boundaries embedded within multipart boundaries, essentially message parts within message parts, the embedded parts will not be found. During my testing I found that this occurs when an embedded image appears in the email html text. I solved the problem using recursion. Essentially passing the start and stop lines of the multipart found back into the parser (Pop3MessageComponents) to decode any nested parts.

If you need to decode email with large amounts of Quoted-Printable text you can speed up the decoder by using byte arrays instead of strings. There is also a bug in the decoder. You must also replace "=20\n" with a " " in addition to the already existing "=\n".

The code does not save all types attachments so if you need them you will need to add code for it. Also, the attachment directory is hard coded so you may want to change that.

The previous postings about bug fixes were mostly helpful and specifically the ones to trim lines and warn of issues with very, very large messages. I was mislead by some of the previous posting as their fixes did more harm than good. There is one posting that uses a "while (true)" as part of the fix. I would avoid it. There is an earlier posting which fixes that bug and does not run the potential for an infinite loop.

In total I spent about 12 hours to get the code working for what I needed to do.

modified on Wednesday, November 26, 2008 6:22 PM

GeneralRe: My Experience With This Code PinPopular
mxmissile19-Jan-09 12:15
mxmissile19-Jan-09 12:15 
GeneralRe: My Experience With This Code Pin
javalace17-Feb-10 18:52
javalace17-Feb-10 18:52 
GeneralOnly work with out look Pin
Umesh873823-Oct-08 19:39
Umesh873823-Oct-08 19:39 
GeneralRe: Only work with out look Pin
jhrees22-Nov-08 12:26
jhrees22-Nov-08 12:26 
QuestionHow to know Attachment count ? Pin
Umesh873819-Oct-08 21:26
Umesh873819-Oct-08 21:26 
AnswerRe: How to know Attachment count ? Pin
n4cer50028-Apr-09 5:30
n4cer50028-Apr-09 5:30 
GeneralI want to show all attahcment reg. mail in list box. Pin
Umesh873819-Oct-08 19:18
Umesh873819-Oct-08 19:18 
Generalvss problem Pin
snehal7776-Oct-08 18:39
snehal7776-Oct-08 18:39 
Questionlicense ?? Pin
yassir hannoun27-Sep-08 14:01
yassir hannoun27-Sep-08 14:01 
AnswerRe: license ?? Pin
Giacomo_7916-Jun-09 0:21
Giacomo_7916-Jun-09 0:21 
GeneralError on server Pin
rajanivinodnair22-Sep-08 1:29
rajanivinodnair22-Sep-08 1:29 
Questionhow can i run this demo project Pin
venkat_kts18-Sep-08 21:29
venkat_kts18-Sep-08 21:29 
AnswerRe: how can i run this demo project Pin
sskumar12313-Mar-09 1:36
sskumar12313-Mar-09 1:36 
Generalcreate inbox PinPopular
niravpatel014-Sep-08 22:37
niravpatel014-Sep-08 22:37 
GeneralConvert.FromBase64String Error Pin
Member 28636146-Aug-08 21:54
Member 28636146-Aug-08 21:54 
GeneralRe: Convert.FromBase64String Error Pin
dotgambrinus23-Jun-09 22:35
dotgambrinus23-Jun-09 22:35 
QuestionBody Pin
Gabriel Choo21-Jul-08 23:41
Gabriel Choo21-Jul-08 23:41 

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.