UML软件工程组织

用java开发Email工具之接收邮件
作者:冯睿    本文选自:赛迪网  2002年12月20日

目前的电子邮件基本上都是通过POP3网络协议接收的。根据POP3的规定,当一个电子邮件程序需要接收电子邮件时,该程序同POP3服务程序需要建立起双向的传输通道。和SMTP类似,当传输通道成功建立后,电子邮件程序会向POP3服务程序发送一系列基于ASCII字符的命令,而POP3服务程序会对这些命令产生相应的回应来表明相应的操作是成功还是失败了。下图显示了POP3是如何工作的。


POP3协议中定义了很多命令,其中最常用的是USER,PASS,STAT,RETR,DELE和QUIT。和前面一样。当一个邮件程序成功地通过套接字连接到POP3服务器后,POP3服务器程序将向邮件程序发送初始化消息。该消息由一个"+OK"回应码和POP3服务程序的名称和版本信息构成。POP3中只有两种回应码"+OK"和"-ERR",邮件程序只需要根据回应码做出相应的反应,而回应码后的文字信息主要是供人查看的。在收到初始化消息后,邮件程序通过发送USER命令开始邮件传输过程。USER命令指定了用户名(邮箱的名称),作为回应,POP3服务程序需要确认用户名对应的邮箱。如果成功,邮件程序需要发送PASS命令来向POP3服务程序提供邮箱的密码。接着需要发送STAT命令来获得目前在邮箱中电子邮件的数量和每个邮件的大小;或者发送RETR命令提取邮件;也可以发送DELE删除邮件。最后使用QUIT命令退出邮件传输过程。

下面提供了一个基于命令行的例子POP3Demo,这个例子可以帮助你理解基于POP3的邮件传输机制。这个程序将利用标准端口110连接到一个POP3服务程序上。为了使程序能够运行,你需要将home更改为你使用的邮箱的地址。

// POP3Demo.java
import java.io.*;
import java.net.*;
class POP3Demo
{
  public static void main (String [] args)
  {
   String POP3Server = "mail.gatewest.net";
   int POP3Port = 110;
   Socket client = null;
   try
   {
     // 创建一个连接到POP3服务程序的套接字。
     client = new Socket (POP3Server, POP3Port);
     // 创建一个BufferedReader对象来读取用户输入。
     BufferedReader stdin;
     stdin = new BufferedReader (new InputStreamReader (System.in));
     //创建一个BufferedReader对象,以便从套接字读取输出。
     InputStream is = client.getInputStream ();
     BufferedReader sockin;
     sockin = new BufferedReader (new InputStreamReader (is));
     //创建一个PrintWriter对象,以便向套接字写入内容。
     OutputStream os = client.getOutputStream ();
     PrintWriter sockout;
     sockout = new PrintWriter (os, true); // true for auto-flush
     // 显示POP3握手信息。
     System.out.println ("S:" + sockin.readLine ());
     while (true)
     {      
      System.out.print ("C:");
      // 读取用户输入。
      String cmd = stdin.readLine ();
      // 将命令发送到POP3服务程序。
      sockout.println (cmd);
      // 读取POP3服务程序的回应消息。
      String reply = sockin.readLine ();
      System.out.println ("S:" + reply);
      // 如果输入了RETR命令并且返回了成功的回应码,持续从套接字读取输出, 
      // 直到遇到<CRLF>.<CRLF>。这时从套接字读出的输出就是邮件的内容。
      if (cmd.toLowerCase ().startsWith ("retr") &&
        reply.charAt (0) == '+')
        do
        {
          reply = sockin.readLine ();
          System.out.println ("S:" + reply);
          if (reply != null && reply.length () > 0)
            if (reply.charAt (0) == '.')
              break;
        }
        while (true);
      // 如果用户输入了QUIT命令,退出邮件传输过程。
      if (cmd.toLowerCase ().startsWith ("quit"))
        break;
     }
   }
   catch (IOException e)
   {
     System.out.println (e.toString ());
   }
   finally
   {
     try
     {      if (client != null)
        client.close ();
     }
     catch (IOException e)
     {
     }
   }
  }
}

下面是运行POP3Demo的结果:

S:+OK Microsoft Exchange 2000 POP3 server version 6.0 4417.0 (home.digital.com) 
ready
C:user fr
S:+OK
C;pass fr
S:+OK User successfully logged on.

运行POP3Demo后,邮件服务程序首先返回初始化信息。我们可以看到邮件服务器上安装的是微软的Exchange 2000作为邮件服务程序。然后输入USER和PASS命令指定用户名和密码。有些邮件服务程序在登录后会提示用户当前邮箱中是否有新的邮件,例如在Linux下的QPOP会返回类似于这样的信息:

S:+OK fr has 1 message (554 octets).。
C:stat
S:+OK 1 1
通过STAT命令可以查看当前邮箱中邮件的数目,POP3服务程序返回了1 1,表示有一份邮件,一封邮件未读。
C:retr 1
S:+OK
S:Recevied: from gis02 ([23.3.54.53]) by home.digital.com with Microsoft SMT SVC 
(5.0.2195.2966)
S:      Fri, 13 Dec 2002 15:12:37 +0800
S:Message-ID 001401c2a77$04353900$35fw0217@digital.com
S:From: "=?gb2312?B?t+vuow==?=" fr@digital.com
S:To: fr@digital.com
Subject: Test Email
This is the test Email.

然后就可以发送RETR命令来接收邮件了。RETR的参数代表了邮件的编号,1代表最新的邮件。这封邮件就是刚才通过SMTPDemo发送的邮件。有一点需要注意,在发送的时候我并没有指定From:头,那么From:头是从哪里来的呢?当发送邮件的时候,如果SMTP服务程序如果没有检测到From:头,会将MAIL命令后的参数作为From:头的内容。

C:dele 1
S:+OK
C:stat
S:+OK 0 0

使用DELE命令可以删除指定的邮件,这里我删除了序号为1的邮件。删除后,在利用STAT命令查看邮件时,就会返回0 0,表示现在邮箱里没有邮件。
C:quit
S:+OK Microsoft Exchange 2000 POP3 server version 6.0 4417.0 signing off.

最后使用QUIT命令中断与POP3服务程序的通讯。
小结

Java的网络API可以用来编写很多有用的程序,例如收发电子邮件的程序。在这篇文章中,我们了解了电子邮件的结构以及如何使用SMTP和POP3协议来发送和接收邮件,同时也了解了MIME是如何支持附件的。



版权所有:UML软件工程组织