Click here to Skip to main content
Email Password   helpLost your password?

Introduction

The .NET framework 2.0 has revamped the support of email sending with improved SMTP classes, but receiving emails is still missing. There are various articles on CodeProject for POP3 support, but all have some drawbacks such as

This project builds on the previous projects, but is written entirely in C# 2.0. The present first article focuses on the downloading of raw emails from a POP3 server (RFC1939). There are methods to connect to a POP3 server, to get a list of available emails, to request some emails, to delete some emails and to disconnect. For debugging and for professional use, extensive error reporting and communication tracing is provided. A future article will decompose the received raw email into body, alternative views and attachments following the MIME specification.

I used Gmail for testing, which is freely available for anyone (recommended).

This code is based on the following work:

Background

Interacting with a POP3 Server

Downloading an email from a POP3 server is rather straight forward. The communication with a POP3 server uses only few commands and is easily human readable. Once a connection, possibly with SSL, is established, the client needs to provide a user name and password to enter the POP3 state TRANSACTION, called 'connected' in Pop3MailClient.

In the connected (POP3: transaction) state, the client can execute the following commands:

For a better understanding, it is recommended to read the official POP3 specification, RFC1939 from IETF: Post Office Protocol - Version 3.

Error Handling & Tracing

Quite a number of things can go wrong when two computers communicate over the Internet. Therefore, solid error reporting and communication tracing is essential. Some problems, like no response form the server are fatal and throw an exception. After an exception, usually the connection is dead and needs to be rebuilt. If the error is detected by the POP3 client code, a Pop3Exception (inherited from ApplicationException) is thrown, otherwise it is a normal .NET exception. Some problems, like trying to retrieve a non existing email, raise just a Warning event. It is up to the user of the POP3 client code to decide if an exception should be thrown in the Warning event or a warning written into a log file or ... After a warning, the POP3 server is ready for the next command.

To further help with the investigation of communication problems, a Trace event is raised. It shows commands and responses exchanged between PopClient and PopServer, including warnings. It is strongly recommended to use this feature in the beginning of a project, because RFC1939 gives the server implementor great freedom. It often provides additional information which can be seen in the trace.

Using the code

Server Settings

I feel the server settings like IP address, etc. should not change within a session. The Pop3MailClient requires servername, port, should SSL be used, username and password in the constructor and they cannot be changed. If you want to connect to a different server or for a different user, create a new Pop3MailClient.

To get the demo code running, you need to enter your own credentials for username and password in the following line:

// TODO: Replace username and password with your own credentials.

Pop3.Pop3MailClient DemoClient =
  new Pop3.Pop3MailClient(
    "pop.gmail.com", 995, true, "Username@gmail.com", "password");

If you don't use Gmail, of course you need to also change the servername and port number, maybe even set useSSL to false.

Reading Raw Email

The method GetRawEmail returns the complete email content for one particular message number. RFC1939 specifies that only ANSI characters can be used and therefore the raw email can be easily displayed. But of course it might look funny because of special characters or encoding. Decoding an email will be part of the next article about my Pop3MimeClient class.

AutoReconnect after server timeout

I tested the code extensively with Gmail, which sometimes simply fails to respond. If the isAutoReconnect property is set, the Pop3MailClient tries to reconnect exactly once after a timeout. That's all it usually takes, but notice that any emails marked for deletion are not deleted on the server.

Points of Interest

Efficiency

My guess is that the garbage collector spends a considerable amount of time with collecting memory. Receiving email is a lot of text processing and the idea of all these strings created and discarded gives me a creepy feeling. I hear you saying, use Stringbuilders, but they can be even slower than strings if only few operations are executed with them. Isn't it time for some recycling, i.e. reusing the same global StringBuilder for every email received? I was careful not to introduce any concurrency problems. But even the Framework itself is not reentrant ! If the repeated use of StringBuffers troubles you, just make them local.

Gmail

I had a good experience using Gmail, although I encountered 2 flaws:

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralReading email seems to be failing [modified]
Caden
7:55 17 Dec '09  
Thanks for putting this together, it definitely helps to fill in a few blanks, I guess not many people are publishing this stuff.

Running the script as is, with new credentials for logging in (using vs.net 2003 to compile) it validates, views an incorrect number of emails in my inbox, pulls an obscene amount of lines and characters without actually displaying what they hold just says x lines and x characters... I guess its worked better than any of the non SSL examples I've tried which fail entirely due to a lack of security support, but I still can't actually read an email with this.

Also noted, it always retries when it comes to pulling the raw email and always gives me a negative response for ID 1000000, not sure what that means either. There are also always number out of range exceptions...

Any suggestions would be appreciated.

EDIT: Upon looking a bit deeper into the code, I found that the exchanges were being made but values weren't being output to screen as I'd anticipated, I'm not used to console applications. Smile It seems to be working very well, I was able to download my email, thanks again for an awesome example!

modified on Thursday, December 17, 2009 1:25 PM

GeneralHow to decode the subject?
Mikla78
6:12 25 Nov '09  
Hi all

I'm quite a beginner in programing, so I already apologize if my question seems obvious or even stupid to you.
I tried the whole day long, in vain, to get the email subject decoded, for instance

Subject: =?utf-8?Q?Trend_Micro_Internet_Security_es?=
=?utf-8?Q?t_activ=C3=A9?

Subject: =?koi8-r?B?R2V0IGEgZGVjZW50IHdhdGNoIHlvdSB3b26SdCBiZSBhc2hhbWVkIG9m?=
=?koi8-r?B?Lg==?=

or
Subject: =?iso-8859-1?B?UGFzc2V6IGQndW4gc3lzdOhtZSBkJ2luZm9ybWF0aW9uIOAgdW4gYXV0cmUgOiB1biA=?=
=?iso-8859-1?B?bGl2cmUgc3VyIGxhIG1pZ3JhdGlvbiBkZSBkb25u6WVz?=

Could any one help me here? If possible could you provide me with a bit of straightforward code, it would be great!
Thanks

Michaël
GeneralRe: How to decode the subject?
Peter Huber SG
14:18 25 Nov '09  
The subject uses not the standard character set, that's why it looks so funny. I didn't have the time to add support for international character sets in the subject line. You would have to check the relevant RFCs and implement it yourself. I am not sure, but if you are lucky, you might find a message of someone who did that already.
GeneralMark message as read
thomasabcd
10:20 21 Sep '09  
Hi,

I am using your excellent pop3client. Is it possible to have it mark a message as read, so it doesn't download it again? Or do I have to delete the message after it has been downloaded to prevent it from being downloaded again? I like storing all my emails in the inbox for future reference, and only download the new ones.

Thanks
Thomas
GeneralRe: Mark message as read
tokfrans
6:21 5 Oct '09  
I don't think you can mark a message as read on the server, you have to keep track of what e-mails have been read yourself.

/Timmy
Generalsmall real world(?) patch
tb2000
5:19 17 Sep '09  
Hi Peter

thanks first, nice piece, up working in less than an hour!

One find where exceptions where thrown - assume it is a real world exposure issue on the server I am accessing. Maybe worth for others to share:
In Pop3MimeClient.cs the parser apparently ran across the same key twice and could obviously not reregister it, not sure thats intended.
Here's my patch - just ignore the repeated key; not sure which value would have the higher validity/priority though (if).
I am not a MIME expert - so any comments are welcome.

foreach (string key in messageContentDisposition.Parameters.Keys) {
if (!AttachmentContentDisposition.Parameters.ContainsKey(key))
{
AttachmentContentDisposition.Parameters.Add(key, messageContentDisposition.Parameters[key]);
}
}
Thanks again & cheers

tb
GeneralHow to Track Bounce Back Email
gowrikaran1984
4:00 14 Aug '09  
hi I need to get mail address and body which mail bounced please..
GeneralRe: How to Track Bounce Back Email
Peter Huber SG
16:31 14 Aug '09  
When you mention bouncing emails, it seems you are writing about sending emails, which is SMTP, System.Net.Mail. This article is about POP3. Of course, some email server will send you an email back if something goes wrong. Those emails you can read as any other email.

Did you see my other article: POP3 Email Client with full MIME Support (.NET 2.0)[^]
Generali'm attempting a re-write
Yankee Imperialist Dog!
10:43 13 Jul '09  
I'm attempting a re-write more so to help me understand your work than to fix problems. I have to admit i'll be breaking it up a bit to get more special purpose functionality. This is truly a great gift you've given all of us. I want to offer the project i'm creating on my own web site, but i will make sure it is clearly understood that the real work was done here. Also it will not appear unless you give permission and there really is a reason interms of differences to offer it. Otherwise i'll just include a link to this (and the other article) thanks KES

Share the knowledge.
I can use all the help I can get and so do YOU!
KES

GeneralAttachments.
Igor1111111
22:48 6 May '09  
How to save attachemts file?
GeneralRe: Attachments.
tb2000
5:22 17 Sep '09  
Maybe a little late - just figured that out myself for a binary attachment,
maybe others need a different encoding treatment:

if (Extract)
{
foreach (var att in mm.Attachments)
{
if (att.ContentDisposition.DispositionType ==
DispositionTypeNames.Attachment
&& att.TransferEncoding == TransferEncoding.Base64)
{
MemoryStream ms = (MemoryStream)att.ContentStream;
BinaryWriter bw = new BinaryWriter(
new FileStream(att.Name, FileMode.Create));
bw.Write(ms.ToArray());
bw.Flush();
bw.Close();
Console.WriteLine("Received: " + att.Name);
}
}
}
cheers
tb
Questionhow to get count of unread email?
chjlcn
19:40 11 Oct '08  
how to get count of unread email?

http://chjl.cn
QQ: 287800360

Generalgmail usage, is there a way
hesaigo999ca
10:19 8 Oct '08  
It seems that gmail has some stuff about being able to get this to work using the pop3....can you verify that your utility is able to retrieve gmail messages please, as I would like to know if the errors I am getting is purely because of my router . firewall or because gmail just doesnt allow it. If there is anything special i need to do with your code to make this work for gmail, please let me know....thanks!

Thanks for a great job!
GeneralSuparb Ummmmmmh u are genius... and true Social Worker
Member 4498912
20:21 25 Sep '08  
U are hust heroes of peoples like us who just started carrier.
Keep on going man.
u are just great.......
GeneralThank you!
Tomi84
1:36 5 Sep '08  
I was googling articles about 'Gmail's POP3 SSL access in C#' for weeks!

Thank you!
QuestionRegarding downloading new mails
Dashrath Wasmatkar
20:33 31 Aug '08  
I have implemented a program in Visual C++ 2008 to receive mails through POP3.Through this program, I store date and time of last mail received, just to ensure that next time only new mails get downloaded.This is being done by comparing the stored date and time with all the mails stored in mailbox.If a mail has date and time greater than the datetime already stored, that mail gets downloaded.Upto this everything works fine.

But problem comes, when a new mail comes which contains date and time less than date and time already stored.This mail is a delayed mail, but now in mailbox,it is new because it is not checked yet.Please tell me how to solve this problem.

Also do you know, how email clients or gmail mark a mail as "already read" or "not read yet"?
Please help me.
GeneralWell Done
Randy Charles Morin
5:54 3 Jul '08  
Very well written.

Randy
GeneralThank you!
msdevdude
20:15 3 May '08  
I like how you point out the problems with the other source downloads on the Internet. Thanks for your contribution!
GeneralThank you
net_prog
12:53 12 Mar '08  
This code has really helped me. Works perfectly.
GeneralRe: Thank you
Peter Huber SG
16:32 12 Mar '08  
Thanks for this positive feedback, it makes my day Smile
GeneralHow to skip downloading an attachment?
Raul Rupsingh
16:55 2 Feb '08  
In Pop3.Pop3MimeClient :: ProcessMimeEntity

There's a point where you've figured out the header for the latest Mime entry, and you begin to download the message, line by line.

At this stage you'll know by current element's content disposition that you have an attachment, like a PPT or PDF or something.

Is there any way you can speedup the POP read to just skip the attachment? (skipping ahead in the stream or something?)

Currently it reads each line of the element until you get to a "parentBoundaryEnd". But this can be irritating when you're syncing up to an account and don't want it downloading large attachments you're not going to even use.

Any input is appreciated, thank you!
AnswerRe: How to skip downloading an attachment?
Peter Huber SG
5:03 4 Feb '08  
You use POP3 to communicate with the email server. POP3 has no idea of MIME or what an attachment is. If you start to download an email, you cannot stop it in the middle. POP3 will deliver the complete email.
GeneralRe: How to skip downloading an attachment?
hesaigo999ca
10:22 8 Oct '08  
I thought there was however commands to download just the headers of a message instead of the whole thing...then when you want the message completely, you would use the message id to get that particular message.
I am not sure, but I seemed to remember that the header also contained whether that message contained an attachment or not....???
GeneralRe: How to skip downloading an attachment?
Shlomy
5:07 19 Mar '09  
You are correct, there is a command to get the email headers only.
It is called TOP. (usage: TOP {EMAIL_ID} {LINES})
where EMAIL_ID is the email identification number (usually between 1 to 255 in gmail)
and the LINES is the number of lines of the body you want to read (0 means only headers and no body lines at all, which effectifivly speed up the downloading time very much!

however, i didnt find any indication in the headers of the existing of an attachment in the email.

does anyone has any idea, where it can be found? if at all?
GeneralSolution to error retrieving messages
tbrewer
12:42 23 Jan '08  
I found that in some cases calling 'GetRawEmail' would only retrieve part of the raw message text, causing the POP3 client to return NULL values for all subsequent 'GetRawEmail' requests. I dug into this further and found it was caused by the StreamReader.ReadLine in the 'readMultiLine' method returning corrupted text. Once in a while this corruption will cause the method to find an end of message flag ('.') in what is in fact the middle of the message causing it to stop retrieving the message data early.

I modified 'GetRawEmail' to resolve this:

public bool GetRawEmail(int MessageNo, out string EmailText)
{
int iLength = GetEmailSize(MessageNo);
//send 'RETR int' command to server
if (!SendRetrCommand(MessageNo))
{
EmailText = null;
return false;
}

//get the lines
//string response;
int LineCounter = 0;
//empty StringBuilder
if (RawEmailSB == null)
{
RawEmailSB = new StringBuilder(100000);
}
else {
RawEmailSB.Length = 0;
}
isTraceRawEmail = true;

/* while (readMultiLine(out response))
{
LineCounter += 1;
}
*/

NetworkStream stream = (NetworkStream)pop3Stream;
while (stream.DataAvailable)
{
byte[] bData = new byte[serverTcpConnection.ReceiveBufferSize + 1];
stream.Read(bData, 0, bData.Length);
RawEmailSB.Append(System.Text.Encoding.ASCII.GetString(bData));
}

EmailText = RawEmailSB.ToString();
TraceFrom("email with {0} lines, {1} chars received", LineCounter.ToString(), EmailText.Length);
return true;
}

The problem is, this only resolves the problem for non-SSL connections. pop3Stream can either be a NetworkStream or an SslStream. Below is the basis of what I changed. Does anyone know how to accomplish the equivalent of this with an SslStream?


NetworkStream stream = (NetworkStream)pop3Stream;
while (stream.DataAvailable)
{
byte[] bData = new byte[serverTcpConnection.ReceiveBufferSize + 1];
stream.Read(bData, 0, bData.Length);
RawEmailSB.Append(System.Text.Encoding.ASCII.GetString(bData));
}


Last Updated 5 Aug 2006 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010