用C#.NET实现电子邮件客户程序

周华清 戴晟辉(东华理工学院计算机与通信系 江西 抚州 344000)

【摘要】通过C#这种VisualSTudio.NET中新引入的面向对象且类型安全的编程语言,在.NET平台上开发电子邮件客户程序。通过套接字编程实现网络通信连接,阐述SMTP(简单邮件传输协议)和POP3(邮局协议)的工作原理,然后具体讲解了根据SMTP协议开发电子邮件客户端的邮件发送程序,根据POP3协议开发电子邮件客户端的邮件接收程序。

【关键词】套接字  简单邮件传输协议  邮局协议

1 C#中套接字的编程

套接字是通信的基石,是支持TCP/IP协议网络通信的基本操作单元。可以将套接字看做不同主机间的进程进行双向通信的端点,它构成了单个主机内及整个网络间的编程界面。套接字存在于通信域中。通信域是为了处理一般的线程通过套接字通信而引进的一种抽象概念。套接字通常和同一个域中的套接字交换数据(数据交换也可能穿越域的界限,但这时一定要执行某种解释程序)。各种进程使用这个相同的域互相之间用Internet协议簇来进行通信。

针对C#中Socket编程用Socket类来进行,.NET 框架的Socket类是包含在System.Net.Sockets名字空间中的一个非常重要的类,其中为实现网络编程提供了大量的方法。使用Socket类开发windows网络应用程序原来有规可寻,它们在大多数情况下遵循大致相同的步骤。

在使用之前,你需要首先创建Socket对象的实例,这可以通过Socket类的构造方法来实现:

public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolType);

其中,addressFamily参数指定Socket使用的寻址方案;socketType参数,指定Socket的类型;protocolType参数,指定Socket使用的协议。

下面的示例语句创建一个Socket,它可用于在基于TCP/IP的网络(如Internet)上通讯。

Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

若要使用UDP而不是TCP,需要更改协议类型,如下面的示例所示:

Socket s=newSocket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

一旦创建Socket,在客户端,将可以通过Connect方法连接到指定的服务器,并通过Send/SendTo方法向远程服务器发送数据,而后可以通过Receive/ReceiveFrom方法从服务端接收数据;而在服务器端,你需要使用Bind方法绑定所指定的接口使Socket与一个本地终结点相联,并通过Listen方法侦听该接口上的请求,当侦听到用户端的连接时,调用Accept完成连接的操作,创建新的Socket以处理传入的连接请求。使用完Socket后,记住使用Shutdown方法禁用Socket,并使用Close方法关闭Socket。

2 SMTP和POP3协议的工作过程

在Internet上发送/接收电子邮件,要用到二个协议:SMTP(简单邮件传输协议)和POP3(邮局协议)。下面从SMTP和POP3协议入手,说明如何发送和接收电子邮件。

如图1,描述了从发件人使用主机(Client1)发送一封邮件从邮箱one@server1.com发往邮箱two@server2.com(其中域名为server1.com的邮件系统安装在Server1上,域名为server2.com的邮件系统安装在Server2上),收件人通过主机(Client2)接收到这封邮件的过程。在邮件传送的各个阶段要采用不同的网络协议。

(1)发件人采用Mail Client端软件在Client 1处撰写一封邮件发给收件人,首先是将该邮件从Client1发送到他本人的邮箱one@server1.com所在的服务器Server1上。这一步由Client1发往Server的过程采用的是SMTP协议。

图1 电子邮件传送过程示意图

(2)邮件可以从发件人的邮件服务器Server1直接传送到收件人邮箱two@server2.com所在的服务器Server2上,也可能需要经过第三方的邮件服务器Server3做中转后再送达接收方,这个过程称为Relay。这一步在Mail Server之间进行邮件传送的过程采用的是SMTP协议。邮件发送到接收方的服务器Server2上后,由Server2负责将该邮件投递到收件人的邮箱two@server2.com中,保存在Server2的磁盘阵列中。此时,邮件传送过程结束。

(3)收件人访问他在Server2上的邮箱two@server2.com时,采用Mail Client端软件Client2将Server2邮箱中的邮件下载到本地硬盘上阅读。这一步将邮件从Server下载到Client的过程采用的是POP3协议。

开发电子邮件客户端实际上也就是利用套接字(Socket)编程进行对话通讯,按照SMTP协议和POP3协议的规范完成邮件传输。

3 邮件发送模块的实现

SMTP协议是TCP/IP协议栈中的一个广为使用的上层协议。SMTP定义了如何在两个用户间传输邮件,使用了spooling的概念,允许将邮件从一个本地应用发送到一个SMTP应用。SMTP应用把邮件存储到一个设备或内存中,一旦邮件到达SMTP应用,该邮件被放入到一个队列中,一个服务器检查是否有邮件到达,然后试图投递到达的邮件。如果邮件的收方不存在,服务器然后还会再进行尝试。最终,如果邮件不能被投递,则将该邮件丢弃或返回给邮件的发送者。这一概念被称为端到端的投递,并且它将邮件保存在队列中,直到邮件被投递出去。我们可以从两个RFC中找到有关SMTP的讨论。RFC822描述了报文的结构,其中还包括了信封。RFC821规定了在两台机器间控制邮件交换的协议。

以下模块利用TcpClient类开发一个SMTP客户端,以发送邮件。

3.1 发送SMTP命令

SMTP服务器一般都识别UTF8码,所有发送命令都使用UTF8编码,每个命令均以回车换行符结束。下列代码实现命令的发送功能。

private void WriteToNetStream(ref NetworkStream NetStream.string Command)

{  string stringToSend = Command + "\r\n";

Byte[] arrayToSend = System.Text.Encoding.UTF8.GetBytes

(stringToSend.ToCharArray());

NetStream.Write(arrayToSend,0,arrayToSend.Length);}

3.2 答应码的接收

SMTP服务器对每一个都发出响应。下列代码实现接受答应码的功能。

private string ReadFromNetStream(ref NetworkStream NetStream)

{ byte[] bb=new byte[512];

NetStream.Read(bb,0,bb.Length);

string read=System.Text.Encoding.UTF8.GetString(bb);}

3.3 应答码检查

发送邮件客户端必须要检查应答码,以判断服务器是否已经执行了命令。如果服务器没有执行,则重新发送命令或采用其他措施。下列代码可以检查服务器是否正确地执行了命令。

private string checkForError(string strMessage,string check)

{  if (strMessage.Indexof(check) == -1)

{ return "err";}

else{return "correct";}}

上述方法的第一个参数是服务器返回信息,第二个参数是要检查的答应码。如果服务器返回的信息中不存在第二个参数的字符串,则返回“err”,表明服务器没正确执行命令。

3.4 发送邮件

客户端发出DATA命令,在服务器作出354应答后,即可开始邮件内容的发送。邮件以<CRLF>.<CRLF>结束。下列代码实现了邮件发送功能。

private void sendMail(ref NetworkStream NetStream, string message)

{   Byte[] attayToSend = System.Text.Encoding.UTF8.GetBytes

(message.ToCharArray());

NetStream.Write(arrayToSend,0,arrayToSend.Length);}

4 邮件接收模块的实现

POP允许本地邮件UA(User Agent,用户代理)连接SERVER并将邮件取回到用户本地系统,用户也在本地机上阅读和响应消息。POP3UA通过TCP/IP与服务器连接(通常使用端口110)。输入用户名和口令经过认证后,UA可通过POP3命令取回或删除邮件。POP3仅仅是接收协议。POP3UA使用SMTP向服务器发送邮件。

利用POP3协议开发一个邮件接收程序,使用USER、PASS、STAT、LIST、RETR、DELE、QUIT命令。下面开始开发过程。

4.1 发送命令码

在此发送命令码也使用的是ASCII码。下列方法用于向服务器发送命令码:

private void WriteToNetStream(ref NetworkStream NetStream.string Command)

{   string stringToSend = Command + "\r\n";

Byte[]arrayToSend= System.Text.Encoding.ASCII.GetBytes

(stringToSend.ToCharArray());

NetStream.Write(arrayToSend,0,arrayToSend.Length);}

4.2 接收服务器应答

一般而言,接收服务器应答,既可使用ASCII码,也可以使用UTF8码,这里使用的是ASCII码。下列方法用于接受服务器的应答。

private string ReadFromNetStream(ref NetworkStream NetStream)

{  byte[] bb=new byte[1024];

NetStream.Read(bb,0,bb.Length);

string read=System.Text.Encoding.ASCII.GetString(bb);

return read;}

4.3 接受邮件

在此接收邮件用UTF8码,当遇到<CRKF>.<CRLF>,则结束读取数据。下列代码用于接收邮件:

private void ReadMail(ref NetworkStream NetStream,int number)

{  int k=0;

bool check=false;

byte[] bb=new byte[6400];

while(!check)

{ k=NetStream.Read(bb,0,bb.Length);

string read=System.Text.Encoding.UTF8.GetString(bb,0,k);

int x= read.IndexOf("\r\n.\r\n");

if(x!=-1)

{ check=true;}

richTextBox2.AppendText(read);

WriteToNetStream(ref

NetStream,"DELE "+number.ToString());

string back=ReadFromNetStream(ref NetStream );

richTextBox1.AppendText("DELE "+number.ToString()

+"命令应答:"+back+"\r\n"); }}

5 结束语

把邮件发送模块和邮件接收模块合起来,就成为一个电子邮件的客户端程序。在实际应用中,在上面基础上加以改进,如果再进一步结合数据库技术,这可以开发出易用、可靠的电子邮件的客户端程序。

(收稿日期:2004-02-25;电子邮件:zhouhuaqing@peoplemail.com.cn

 

Programming e-mail client with c#.net

Abstract: Develop a program for e-mail client on the flat of .net with C#. C# is a new language of visual studio .net , is modern, object-oriented and is safe in type. Realize the network correspondence depending Socket programming. Expatiate the principle of SMTP(Simple Mail Transfer Protocol) and POP3(Post office Protocol), then explain developing a program to send e-mail according to the SMTP agreement development E-mail mail customer and carry to receive the procedure developing a program to receive e-mail according to the POP3 in detail.

Key Words: Socket; Simple Mail Transfer Protocol; Post Office Protocol

参 考 文 献

[1]谢希仁. 计算机网络. 第2版. 北京:清华大学出版社,1999

[2]Charles Petzold. Windows程序设计. 第5版. 北京:北京大学出版社,1999

[3]Anthony Jones 和 Jim Ohlund.  Windows网络编程. 第2版. 北京:清华大学出版社,2002

用C#.NET实现电子邮件客户程序的更多相关文章

  1. UNIX网络编程——非阻塞connect: Web客户程序

    非阻塞的connect的实现例子出自Netscape的Web客户程序.客户先建立一个与某个Web服务器的HTTP连接,再获取一个主页.该主页往往含有多个对于其他网页的引用.客户可以使用非阻塞conne ...

  2. NanoPC-T4/RK3399开发板Ubuntu FriendlyCore系统开机自动运行客户程序

    RK3399开机自动运行客户程序 比如hellohello.c 交叉编译:aarch64-linux-gcc hello.c -o hello使用SecureCRT软件通过串口下载到开发板rz修改文件 ...

  3. UNIX网络编程——非阻塞connect:时间获取客户程序

    #include "unp.h" int connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec) ...

  4. TCP回射客户程序:str_cli函数

    str_cli函数完成客户处理循环: 从标准输入读入一行文本,写到服务器上,读回服务器对该行的回射,并把回射行写到标准输出上 读入一行,写到服务器 fgets读入一行文本,writen把该行发送给服务 ...

  5. TCP回射客户程序:main函数

    创建套接字,装填网际网套接字地址结构 创建一个TCP套接字,用服务器的IP地址和端口号装填一个网际网套接字地址结构 我们可从命令行参数取得服务器的IP地址 从头文件unp.h取得服务器的众所周知端口号 ...

  6. 隐式intent启动电子邮件,不需要非电子邮件应用程序。

    Intent intent = new Intent(Intent.ACTION_SENDTO); intent.setType("text/plain"); intent.put ...

  7. 非阻塞connect:Web客户程序

      一.web.h #include <stdio.h> #include <netdb.h> #include <errno.h> #include <fc ...

  8. C++实现 电子邮件客户端程序(简易版)

    #Windows操作系统下 用命令行工具实现发送邮件(编程前工作) 步骤: 1.telnet连接服务器(以用QQ邮箱向网易邮箱发送邮件为例,端口号25) 2.返回220 说明连接成功 3.ehlo发送 ...

  9. 如何导入和导出应用数据通过电子邮件应用程序在你的IOS

     本文转载至 http://blog.csdn.net/zaitianaoxiang/article/details/6657887 http://yueding920.blog.163.com/bl ...

随机推荐

  1. AFNetworking教程

    转:http://www.lanrenios.com/tutorials/network/2012/1126/527.html AFNETWORKING AFNetworking他是一个现在非常用得多 ...

  2. HDU 5114 Collision

    Collision Time Limit: 15000/15000 MS (Java/Others) Memory Limit: 512000/512000 K (Java/Others) Total ...

  3. 对delegate进行扩展 打造通用的"计时完成"方法 z

    让用户尽量少打字 每次让用户输入这么多信息的确很糟糕, 可以改进一下设计: 服务器IP和用户名可以存放在配置文件里面, 初始化的时候默认加载到相应的文本框中; 从安全角度考虑, 密码必须经过用户手动输 ...

  4. C++实现ping功能

    今天接到需求要实现ping的功能,然后网上查了一些资料,对网络编程的一些函数熟悉了一下,虽然还有一些细节不清楚,但是慢慢积累. 要实现这样的功能: 基础知识 ping的过程是向目的IP发送一个type ...

  5. java 复习001

    java 复习001 比较随意的记录下我的java复习笔记 ArrayList 内存扩展方法 分配一片更大的内存空间,复制原有的数据到新的内存中,让引用指向新的内存地址 ArrayList在内存不够时 ...

  6. Standalone HBase

    This is the default mode. Standalone mode is what is described in the quickstart section. In standal ...

  7. A题进行时--浙大PAT 1021-1030

    1021: #include<stdio.h> #include<string.h> #include<vector> #include<queue> ...

  8. 基础排序算法,java实现(快速,冒泡,选择,堆排序,插入)

    1.冒泡排序: (1)比较相邻的元素.如果第一个比第二个大,就交换他们两个. (2)外面再套个循环就行. 算法复杂度:O(N2)   不罗嗦,上代码: //冒泡排序(两两交换,外加一个外循环) pub ...

  9. Hadoop 2.6.0 POM.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  10. OpenCV中IplImage和Mat间的相互转换

    OpenCV中做图像处理经常用到IplImage和Mat间的相互转换. 首先,cv::Mat是opencv2.0中的数据类型:IplImage是opencv1.0中的类型,两种类型并不相同. 1. I ...