Click here to Skip to main content
Click here to Skip to main content

A POP3 Client in C# .NET

By , 9 Feb 2004
 

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:

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

You then open the Inbox as follows:

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:

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)

About the Author

Desmond McCarter
Web Developer
United Kingdom United Kingdom
Member
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!

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 4membernandakumar5319 Apr '13 - 18:58 
Good Explanation
QuestionI can't read the subject correctly !memberCoderMan200721 Jan '13 - 21:19 
My subject is: Microsoft Outlook Test Message
But I see it : =?utf-8?B?TWljcm9zb2Z0IE91dGxvb2sgVGVzdCBNZXNzYWdl?=
Confused | :confused:
Help me please.
Thank you.
AnswerRe: I can't read the subject correctly !memberlesnikowski4 Apr '13 - 1:47 
It does not support any other encoding apart from ASCII.
 
Try this:
www.limilabs.com/mail
GeneralMy vote of 3memberCoderMan200721 Jan '13 - 21:18 
Thank you
but I can't read by subjects!
My subject is: Microsoft Outlook Test Message
but shows me: =?utf-8?B?TWljcm9zb2Z0IE91dGxvb2sgVGVzdCBNZXNzYWdl?=
 
please help me
QuestionHealpmemberg_estrada11 Dec '12 - 7:47 
Not working for gmail
 
Please healp
 
....
BugFail when retrieving attachmentmemberWrangly25 Sep '12 - 21:45 
Hi,
 
thanks for this excellent lib.
I have a problem with some mails, the code fails to retrieve the attachment; I have located the problem but not fixed it:
 
in Pop3Component, in the DecodeData() method, the m_contentDisposition contains the following value :
 
attachment; filename="BOE1021735.txt"
 
"BOE1021735.txt" represents the attachment file which is Base64 encoded in the body and therefore the if is skipped and no file is written.
 
can you, please, fix this ?
I can send you the full email raw data if needed.
 
thanks in advance,
sincerly,
Domi.
GeneralRe: Fail when retrieving attachmentmemberVaratharajan P.7 Oct '12 - 20:13 
I too have the same problem in reading the attachment.
 
But I found one thing quite strange is that, when I forward the same mail, I am able to read it.
It's the first time the attachment is not detected
 
Anyone pls help?
QuestionPop3Client.Datememberjon.hayward6 Sep '12 - 3:21 
I have been using this code for quite awhile now and it works great. But I have just been testing a new mail account, my code hasn't changed but I now get an exception when I call Pop3Client.Date exception: Method not found: 'System.String Pop3.Pop3Client.get_Date()'.
 
Anyone any ideas.
Questionsaving the attachmentmemberMember 849115428 Jun '12 - 19:20 
Does you project provide the facility of saving the attachment also?
Questionwhile (email.NextEmail()) failsmemberMember 363466811 Jun '12 - 9:17 
No idea why, it worked like a charm before. but when I call while (email.NextEmail()) to loop through the mails, it fails on me.
I haven't been able to find a reason. Exept if I dig down, it has a socket thing in there. No idea if this is the reason, or if this is the reasult of the actual fault i'm having.
 
Anyone any idea ?
QuestionIs it possible to get the source of the email?membershacky19 Mar '12 - 17:50 
Hi Guys,
 
Can i ask if it is possible to get the internet header/message source of the email that you read from the email server?
GeneralMy vote of 4memberXmjX15 Feb '12 - 19:28 
Great code works for me
GeneralRe: My vote of 4memberMember 788269815 Mar '12 - 10:51 
Hi,Xmjx
I met some problem when use this pop3client^^
 
int byteCount =
                    m_socket.Receive(buffer,buffer.Length,SocketFlags.Peek);
 
                line =
                    Encoding.ASCII.GetString(buffer, 0, byteCount);
 
Here byteCount is 0.
Should i change the params for m_socket.Receive(buffer,buffer.Length,0)?
Thank you
Suggestionthanks for allmemberalex211b9 Feb '12 - 22:06 
just replace Socket with ProxySocket
http://www.mentalis.org/soft/class.qpx?id=9
and get much more functionality
Questionheader remaining emptymemberConrad Cassar25 Jan '12 - 3:04 
I am tying to use the POP3Client with a Gmail account, which I'm not sure if it is possible.
I am having the Exception: ArgumentOutOfRangeException as the value of the variable header is remaining empty "".
QuestionNot able to read autogenerated mail coming in mail boxmemberpavan_contractor14 Dec '11 - 19:08 
My application uses POP3Client to read unread mails in Inbox. It is not working for some mails which are autogenerated from somewhere and come to my Inbox.
 
I am getting "Object reference not set to an instance of object" error.
GeneralMy vote of 5memberSamNaseri5 Dec '11 - 17:48 
I liked the way you used regular expressions to parse the messages, your code could be a good example for learning regular expressions.
QuestionFor those who need to save, this is how you do itmembercofrari18 Nov '11 - 5:08 
using (BinaryWriter binWriter = new BinaryWriter(File.Open("FilePathAndNameToSaveTo", FileMode.Create)))
{
    binWriter.Write(Convert.FromBase64String(multipart.Data.Replace("\n", "")));
}

AnswerRe: For those who need to save, this is how you do itmemberMember 849115428 Jun '12 - 21:54 
What is multipart ?
AnswerRe: For those who need to save, this is how you do itmemberidShura29 Nov '12 - 19:33 
thanks
QuestionGreat code, but small issue with multiline message bodymemberDougy836 Nov '11 - 22:35 
Thanks very much! Your code has saved me a lot of time Smile | :)
 
In Pop3MessageComponents.cs at Line 39: it strips the newline and concatenates all text - this merges words on different lines together (which is not nice); I changed it to 'AppendLine' which seems to retain readable text without breaking anything else so far.
QuestionHow to download attachments from defined lettersmemberolgofur23 Aug '11 - 3:16 
Hello, I'd like to use your class for work with pop3 but i can't download and save attachments to my computer. Can you show me how can i realise it? Please Smile | :)
QuestionbyteCount getting 0memberrishabhtoshniwal24 Jul '11 - 22:16 
private string GetPop3String()
{
if (m_socket == null)
{
throw new
Pop3MessageException("Connection to POP3 server is closed");
}
 
byte[] buffer = new byte[MAX_BUFFER_READ_SIZE];
// byte[] buffer = new byte[2522575];
string line = null;
 
try
{
int byteCount =
m_socket.Receive(buffer, buffer.Length, 0);


 
line =
Encoding.ASCII.GetString(buffer, 0, byteCount);
}
catch (Exception e)
{
throw new Pop3ReceiveException(e.ToString());
}
 
return line;
}
 
Here i am getting byteCount=0 which raises an exception in this line
if (!header.Substring(0, 3).Equals("+OK"))
{
throw new Exception("Invalid initial POP3 response");
}
QuestionRe: byteCount getting 0memberkaempf8425 Jul '11 - 9:33 
Samee problem, code for that section is throwing an ArgumentOutOfRange exception because the header is returning as an empty string...
 
ByteCount and line are returning 0's between this try...
 
try
{
int byteCount =
m_socket.Receive(buffer,buffer.Length,0);
 
line =
Encoding.ASCII.GetString(buffer, 0, byteCount);
}
catch(Exception e)
{
throw new Pop3ReceiveException(e.ToString());
}
 
return line;

 
At least byteCount is 0, line is returning an empty string ""...
 
Thanks
Kaempf

AnswerRe: byteCount getting 0memberMember 788269815 Mar '12 - 10:38 
Hi,Kaempf
I met the same question^^
Why byteCount is 0? Should i change the params for m_socket.Receive(buffer,buffer.Length,0)?
Thank you

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 10 Feb 2004
Article Copyright 2004 by Desmond McCarter
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid