65.9K
CodeProject 正在变化。 阅读更多。
Home

C# .NET 中的 POP3 客户端

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (156投票s)

2004年2月10日

CPOL

4分钟阅读

viewsIcon

1826996

downloadIcon

55396

一个用 C# .NET 编写的 POP3 客户端,用于读取和处理电子邮件(包括附件)。

引言

很久以前,我曾被要求开发一个软件,用于从电子邮件中提取正文和主题行。“嗯……”,我想,“连接到 110 端口的邮件服务器,发送 POP3 命令,接收数据,搞定!”。确实,在我第一次尝试时,这简直是小菜一碟:读取电子邮件——没问题。我在公司工作的同事们纷纷宣扬我们的能力:“是啊,伙计,我们可以自动处理电子邮件,轻而易举”。

客户随后提出了更多问题:“我们可以将邮件以富文本或 HTML 格式发送吗?”。“是的,当然可以!!”。“关于自动处理呢?”。“嘿——你在和邮件之王说话!!”。“处理多个附件,WAV、MP3、JPEG 呢?”。“呃……我稍后答复你……”。事情并不像我想的那么容易……

起初我发现编写起来相当困难的原因主要是 MIME 的写法以及它初看起来有多么丑陋。这里有一个示例,其中包含两个多部分块(我稍后会解释)。

Received: by Mailserver
        id 01C3EFF7.990BBDF0@TEST; Tue, 11 Feb 2003 17:02:00 -0000
Message-ID: 2CB86919E23ED51191840060080C3DAE02320B76@MAILSERVER
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(多用途互联网邮件扩展):一个快速粗略的指南

通过互联网传输的数据是以字节集合(即 8 位集合)的形式发送的。这些信息包括文本文件、CSV 文件,甚至是 JPEG 或电影。“嘿”,你可能会说,“你不能以字节集合的形式发送二进制数据!”。是的,你可以,只要使用合适的编码方案:例如,使用 base 64 算法(在你的 .NET 框架中查看 System.Convert.ToBase64String 方法)。这些信息(我们在邮件语境中讨论)还包括主题、正文和转发的项目。对于客户端(发送邮件)和服务器(读取邮件)来说,它们应该相互理解,并且为了做到这一点,它们必须遵循(发送和接收数据)MIME 格式。

在上面的 MIME 示例片段中,你可以轻松理解基本字段。

“发件人:” - 谁发送了电子邮件,“收件人:” - 谁收到了电子邮件,“主题:” - 电子邮件的主题,以及“日期:” - 电子邮件发送的日期/时间。

“内容类型:” 决定了电子邮件包含的内容类型。对于简单的文本电子邮件(即没有附件),这通常是“text/plain”。然而,你也可以看到(我希望你确实能看到)这封邮件实际上包含一个附件:test.xls。包含附件的电子邮件的 MIME 内容类型是“multipart/mixed”。这意味着电子邮件包含被分成多个部分的数据:正文和附件(或在此情况下为“附件”)等。边界(boundary="----_=_NextPart_000_01C3EFF7.990BD65A")标识了这些部分的开始和结束。在我这个例子(以及大多数电子邮件)中,正文是这个多部分电子邮件的第一部分。正文的开始由第一个边界声明标识。

------_=_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

从上面的 MIME 文本中,你还可以看到这一部分也包含了它的内容类型,即正文的格式:text/plain。多部分电子邮件的所有部分都有其头部定义,然后是一个空行,然后是实际的正文。

这个多部分电子邮件的下一部分是附件。

------_=_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 实际上是面向对象的

我在构建 POP3 库时犯的第一个错误是使用不适合的语言:C。编写和开发花费了太长时间,而且确实变得非常混乱。开发和测试我的库花费了大约 3 周时间,而在 C# 中,这只需要一天半!!原因在于,可以说,MIME 是一种面向对象的格式:多部分电子邮件的每个部分(即使是简单的 text/plain 邮件的正文 + 主要头部等)都可以被视为对象。这是我用 C# 编写它的主要原因之一(也可以使用 Java 甚至 J2EE,但是……)。

代码

我编写的代码以一个名为 Pop3Client 的类开始。这个类用于实例化与 POP3 服务器的连接。

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

然后,你可以这样打开收件箱:

email.OpenInbox();

要转到第一封电子邮件,然后调用 NextEmail() 方法,如果存在“下一封电子邮件”,它将返回 true,如果不存在这样的电子邮件,则返回 false。还有一个 IsMultipart 单例,你可以使用它来检查电子邮件是否有多部分(即附件)。以下是代码可能样子的示例:

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!");
}

我还在这个类库中实现了其他功能,包括保存附件(目前是自动完成的)的原始格式、获取文件名、扩展名等的 getter。

看看并告诉我你的想法:我确实觉得编写和探索它很有趣!!

© . All rights reserved.