用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