邮件收发系统的实现

摘  要

随着 Internet的迅速发展和普及,网络已经成为人们获取交换信息的重要方式,给人们带来了极大的便利。在各种网络服务中,电子邮件系统以其方便、快捷的特点成为人们进行信息交流的理想工具。通过电子邮件人们可以以十分低廉的价格如现在普遍使用的免费电子邮件,以非常快的速度同世界上其他互联网用户联络。从某种程度上来说,电子邮件已经基本取代了传统的邮局通信方式。电子邮件的使用者数量呈几何级数增长。现在,除了一些必须通过传统的方式进行邮寄的邮件外,一般的日常交流都可以通过电子邮件的形式来进行。 

本文采用了软件工程学方法实现了一个简易电子邮件接收系统的设计与开发,本系统简单地实现邮件的基本功能,包括邮件的接收,发送,读取。可以发送附件等,能对邮件列表进行管理的文件夹,可以进行添加,删除,修改联系人的地址簿。重点着重从客户端和用户界面的开发方面详细阐述了整个电子邮件接收实现的全过程。对开发过程中的难点进行了分析和研究,并通过系统结构图,功能模块图,等方式形象地描述出来,所实现的客户端界面应当是友好美观与易用。

关键词:JSP;JAVAMAIL;TOMCAT;pop3

ABSTRACT

With the rapid development of Internet and the popularization, the network has become an important way of exchange information, has brought people great convenience. In all kinds of network service, electronic mail system with its convenient, quick characteristic become people information communication ideal tool. Through the email people can very cheap price, such as now commonly used free email, with a very fast speed in the world with other Internet users contact. To some extent, email has basically been replaced the traditional post office communication mode. E-mail users quantity is geometric progression growth. Now, in addition to some must be through the traditional way by mail outside, general daily communication can through the email form

This paper adopted the software engineering method is a simple email receiving system design and development, the system simply realize the basic function of mail, including mail receiving, sending, read. Can send accessories, etc., to mailing list management folder, can add, delete, modify contact address book. Key emphatically from the client and user interface development aspects elaborated the whole email receiving the whole process of realization. To the difficulty in the development process are analyzed and studied, and through the system structure, function module chart, etc, to describe the image out of the realization of client interface should be friendly, beautiful and easy to use

Key words:JAVAMAIL   JSP   J2EE  TOMCAT


目  录

第一章 引言

第二章 可行性分析

2.1  JSP技术语法介绍

1.1.1  JSP是什么

1.1.2  JSP技术的特点

2.2  JSPJAVA

第三章 动态网页技术的发展趋势与前景分析

3.1 常见动态网页技术

3.1.1  JSPASPPHPASP.NET

3.1.2  JSP

3.1.4  PHP

3.1.5  ASP.NET

3.2 发展趋势与前景分析

第四章 电子邮件系统设计的相关原理

4.1 系统概述

4.2  电子邮件相关协议及其Java 解决

4.3 字符编码及字符集转换问题

第五章 使用JSP开发邮件系统

5.1 搭建开发环境

5.1.1  该系统运行环境

5.1.2  安装和配置JDK

5.1.3  安装和配置Tomcat

5.1.4  测试是否安装配置成功

5.2  JavaMail简介

5.2.1  安装

5.2.2  使用Java 2企业版

5.3  使用JSP发送邮件

5.3.1  E-MAIL常识

5.3.2   发送普通文本格式的E-MAIL

5.3.3 发送带附件的E-MAIL

5.4  使用JSP接收E-MAIL

5.4.1  显示所有E-MAIL列表

5.4.2  接收普通文本格式的E-MAIL

5.4.3  收带附件的E-MAIL

第六章   电子邮件系统的使用说明

附录:JSP程序原代码

参考文献

 

第一章 引言

网络的迅速发展使得电子邮件已经成为我们必不可少的通信工具,而电子邮件的形式也从原来的纯文本方式变成现在的Html 页面并加载附件的多彩形式。电子邮件的普及性以及其数据的多样性使得它成为人们存储自己重要信息、数据的方式。现代化的移动办公要求我们处理邮件用的客户程序应该可以随时随地的方便使用,而WEB方式的邮件收发系统恰恰满足了这样的需求,这样JSP 结合JavaMail 也就成了邮件收发系统的最佳解决方案。Java 语言一直以其独有的强大的网络能力而著称,JavaMail 的推出无疑再次扩展了Java 的网络能力。然而,虽然Java 提供了Mail 的开发包但要想实现一个邮件系统还要熟悉电子邮件的格式结构,另外在开发中文邮件系统时还要了解Mail 的编码问题以及Java 中的字符集转换问题。本篇文章将介绍如何用JavaMail 结合JSP 建立一个WEB 方式的邮件收发系统(下面简称WEBMAIL),并重点讨论MIME 协议规范以及邮件系统所涉及的数据编码的问题。

第二章 可行性分析

2.1  JSP技术语法介绍

1.1.1  JSP是什么

      JSP是JAVA Server Pages的简称,顾名思义是服务器的一种基于JAVA语言的网页技术。JSP正式发布与1999年6月,它是美国SUN公司倡导,多家公司合作建立的一种功能强大的动态网页技术标准,用于创建可支持平台跨WEB服务器的动态网页。

1.1.2  JSP技术的特点

      JSP提供了一种简单快速的建立基于动态内容显示的技术。它能很好的兼顾开发效率和运行效率,同时满足分布式事件的处理功能,并且具有强大的扩展功能,在不同的系统间的移植性也相当的好。

      JSP的技术特点主要体现在以下几个方面:

  1. 将内容的生成和显示相分离

WEB 页开发人员可以使用HTML标识来设计和格式化最终页面,使用JSP标识或者小脚本来封装页面上的动态内容。这样的好处是其他人,如WEB管理人员或者网页设计者,就能够很方便的抛开JSP标识和小脚本来编辑和使用JSP页面,而不至于影响动态内容。

在服务器端,JSP引擎解释JSP标识和小脚本,生成所请求的内容,并将结果以HTML页面的形式发送回浏览器。这样既有助于作者保护自己的代码,又能保证任何基于HTML语言的WEB浏览器完全可用。

  1. 使用可重用的组件

JSP页面通过可重用、跨平台的组件来执行拥护所要求的比较复杂的处理。开发人员能够共享和交换组件,使得这些组件被更多的开发者或客户团体所使用。基于组件的开发方法加速了总体的开发进程,并且能够最大限度的凝聚、整合各开发人员或组织的智慧和努力,从而构建一个广泛的相互支持的协同开发氛围。

  1. 采用标识简化页面的开发

       WEB开发人员并不都是熟悉脚本语言的编程人员。JSP采用标识封装了许多功能,这些功能实现了与JSP相关的许多动态内容,如访问和实例化组件、存取数据库中的记录、下载APPLET以及执行用其他方法难以实现的功能。通过开发制定标识库,可以对JSP技术进行扩展,还可以让第三方开发人员和其他人员为常用的功能创建自己的标识库,这样WEB人员的开发人员就能够像使用特定的工具一样来使用标识库进行WEB开发工作。

  1. JSP具有JAVA技术所带来的所有优点

       由于JSP页面的内置脚本语言是基于JAVA编程语言的,而且所有的JSP页面都被编译成JAVA SERVLET(SERVLET是运行在JSP服务器端,用来生成WEB页面的一种JAVA程序),所以JSP页面具有JAVA技术的所有好处,包括健壮的存储管理、安全机制和“一次编写,随处运行”等。随着越来越多的供应商在他们的产品中加入对JSP的支持,我们可以在更广阔的范围内选择自己所需的服务器和开发环境,而丝毫不影响针对客户的WEB应用。

  1. JSP容易整合到多种应用体系结构中

我们还可以将JSP扩展到能够支持企业级的分布式应用。作为采用JAVA技术家族的一部分以及J2EE的一个重要组成部分,JSP能够很好的支持高度复杂的基于WEB的应用。

2.2  JSP与JAVA

   JAVA起先源于SUN公司一个叫做GREEN的项目,该项目原先的目的是为家用消费电子产品开发一个分布式通信系统,这样用户就可以把E-MAIL发给电视机、电冰箱、空调等家用电器和它们进行信息交流,对他们进行控制。后来随着全球互联网的迅速兴起,JAVA的特性----平台独立、安全稳定、动态下载、实时互动等越来越受到欢迎。另一方面,随着近年来服务器端的应用日渐受到重视,大家又发现了JAVA在服务器端的优势特性,时至今日,除了微软之外,几乎所有服务器端的应用都以JAVA为标准。JAVA作为软件开发的一种革命性的技术,其地位已经确定下来。

   实际上JAVA的核心技术就是JAVA虚拟机JVM( Java Virtual Mavhine) ,它是JAVA实现其平台无关性的基础。JAVA虚拟机是可运行JAVA代码的假象计算机,只要根据JVM规格描述将解释器移植到特定的计算机上,就能保证经过编译的任何JAVA代码都能在该系统上运行。“Write once, Run Anywhere”(一次编写,随处可运行),就是SUN公司提出的千百万程序员梦寐以求的口号,这无疑是软件业发展史上一次划时代的创举。

   JSP实质上就是一些JSP标记、JAVA程序段以及HTML文件的结合体,它以JAVA语言作为其内置的脚本语言。可以说JSP就是JAVA,知识它是一个很特别的JAVA语言,它实际上是调用了JSP引擎来生成JAVA文件,再将这个JAVA文件编译成类文件,这才能去执行它以生成动态网页。所以说,JAVA有什么功能,JSP就有什么功能。JAVA的平台独立性、安全稳定性、动态下载等诸多优异性在JSP上得到了最充分的体现!

第三章 动态网页技术的发展趋势与前景分析

3.1 常见动态网页技术

3.1.1  JSP、ASPPHPASP.NET 

JSP 全名是Java Server Page,它是SUN公司推出的新一代站点开发语言,他完全解决了目前ASP、PHP的一个通病--脚本级执行(据说PHP4 也已经在Zend 的支持下,实现编译运行).Sun 公司借助自己在Java 上的不凡造诣,将Java 从Java 应用程序 和 Java Applet 之外,又有新的硕果,就是Jsp--Java Server Page。Jsp 可以在Serverlet和JavaBean的支持下,完成功能强大的站点程序。

ASP全名Active Server Pages,是一个WEB服务器端的开发环境, 利用它可以产生和运行动态的、交互的、高性能的WEB服务应用程序。ASP采用脚本语言VB Script(Java script)作为自己的开发语言。

PHP(Personal Home Page)是一种跨平台的服务器端的嵌入式脚本语言. 它大量地借用C、Java和Perl语言的语法, 并耦合PHP自己的特性,使WEB开发者能够快速地写出动态生成页面.它支持目前绝大多数数据库。还有一点,PHP是完全免费的,不用花钱,你可以从PHP官方站点http://www.php.net)自由下载。而且你可以不受限制地获得源码,甚至可以从中加进你自己需要的特色。

ASP.NET又叫ASP+,他不是ASP的简单升级,而是Microsoft推出的新一代Active Server Pages。ASP.NET是微软发展的新的体系结.NET的一部分,其中全新的技术架构会让每个人的编程生活变得更的简单

四者都提供在 HTML 代码中混合某种程序代码、由语言引擎解释执行程序代码的能力但JSP代码被编译成 Servlet 并由 Java 虚拟机解释执行,这种编译操作仅在对 JSP 页面的第一次请求时发生。在 ASP 、PHP、JSP、ASP.NET 环境下, HTML 代码主要负责描述信息的显示样式,而程序代码则用来描述处理逻辑。普通的 HTML 页面只依赖于 Web 服务器,而 ASP 、PHP、JSP、ASP.NET 页面需要附加的语言引擎分析和执行程序代码。程序代码的执行结果被重新嵌入到HTML 代码中,然后一起发送给浏览器。 ASP 、PHP、 JSP、ASP.NET三者都是面向 Web 服务器的技术,客户端浏览器不需要任何附加的软件支持。

技术特点:

3.1.2  JSP

1 JSP将内容的生成和显示进行分离

使用JSP技术,Web页面开发人员可以使用HTML或者XML标识来设计和格式化最终页面。使用JSP标识或者小脚本来生成页面上的动态内容。生成内容的逻辑被封装在标识和JavaBeans组件中,并且捆绑在小脚本中,所有的脚本在服务器端运行。如果核心逻辑被封装在标识和Beans中,那么其他人,如Web管理人员和页面设计者,能够编辑和使用JSP页面,而不影响内容的生成。

  在服务器端,JSP引擎解释JSP标识和小脚本,生成所请求的内容(例如,通过访问JavaBeans组件,使用JDBCTM技术访问数据库,或者包含文件),并且将结果以HTML(或者XML页面的形式发送回浏览器。这有助于作者保护自己的代码,而又保证任何基于HTML的Web浏览的完全可用性。

2 强调可重用的组件

绝大多数JSP页面依赖于可重用的,跨平台的组件(JavaBeans或者Enterprise JavaBeansTM组件)来执行应用程序所要求的更为复杂的处理。开发人员能够共享和交换执行普通操作的组件,或者使得这些组件为更多的使用者或者客户团体所使用。基于组件的方法加速了体开发过程,并且使得各种组织在他们现有的技能和优化结果的开发努力中得到平衡。

  3 采用标识简化页面开发

Web页面开发人员不会都是熟悉脚本语言的编程人员。JavaServer Page技术封装了许多功能,这些功能是在易用的、与JSP相关的XML标识中进行动态内容生成所需要的。标准的JSP标识能够访问和实例化JavaBeans组件,设置或者检索组件属性,下载Applet,以及执行用其他方法更难于编码和耗时的功能。

通过开发定制化标识库,JSP技术是可以扩展的。今后,第三方开发人员和其他人员可以为常用功能创建自己的标识库。这使得Web页面开发人员能够使用熟悉的工具和如同标识一样的执行特定功能的构件来工作。

JSP技术很容易整合到多种应用体系结构中,以利用现存的工具和技巧,并且扩展到能够支持企业级的分布式应用。作为采用Java技术家族的一部分,以及Java 2(企业版体系结构)的一个组成部分,JSP技术能够支持高度复杂的基于Web的应用。由于JSP页面的内置脚本语言是基于Java编程语言的,而且所有的JSP页面都被编译成为Java Servlet,JSP页面就具有Java技术的所有好处,包括健壮的存储管理和安全性。

作为Java平台的一部分,JSP拥有Java编程语言“一次编写,各处运行”的特点。随着越来越多的供应商将JSP支持添加到他们的产品中,您可以使用自己所选择的服务器工具,更改工具或服务器并不影响当前的应用。

应用范围 ASP是Microsoft开发的动态网页语言,也继承了微软产品的一贯传统——只能运行于微软的服务器产品,IIS (Internet Information Server) (windows NT)和PWS(Personal Web Server)(windows 98)上。Unix下也有ChiliSoft的插件来支持ASP,但是ASP本身的功能有限必须通过ASP+COM的组合来扩充,Unix下的COM实现起来非常困难。

    PHP3可在Windows,Unix,Linux的Web服务器上正常运行,还支持IIS,Apache等通用Web服务器,用户更换平台时,无需变换PHP3代码,可即拿即用.

  JSP同PHP3类似,几乎可以运行于所有平台。如Win NT,Linux,Unix. NT下IIS通过一个插件,例如JRUN或者ServletExec,就能支持JSP。著名的Web服务器Apache已经能够支持JSP。由于Apache广泛应用在NT、Unix和Linux上,因此JSP有更广泛的运行平台。虽然现在NT操作系统占了很大的市场份额,但是在服务器方面Unix的优势仍然很大,而新崛起的Linux更是来势不些从一个平台移植到另外一个平台,JSP和JavaBean甚至不用重新编译,因为Java字节码都是标准的与平台无关的。

    性能比较有人做过试验,对这三种语言分别做循环性能测试及存取Oracle数据库测试。在循环性能测试中,JSP只用了令人吃惊的四秒钟就结束了20000*20000的循环。而ASP 、PHP测试的是2000*2000循环(少一个数量级),却分别用了63秒和84秒。(参考PHPLIB)据库测试中,三者分别对 Oracle 8 进行 1000 次Update,Select,和Delete: Jsp 需要 13 秒,Php 需要 69 秒,ASP则 需要 73 秒。

3.1.3  ASP

1使用 VBScript 、 JScript 等简单易懂的脚本语言,结合 HTML 代码,即可快速地完成网站的应用程序。

    2无须 compile 编译,容易编写,可在服务器端直接执行。

    3使用普通的文本编辑器,如 Windows 的记事本,即可进行编辑设计。

    4与浏览器无关 (Browser Independence), 用户端只要使用可执行 HTML 码的浏览器,即可浏览 Active Server Pages 所设计的网页内容。 Active Server Pages 所使用的脚本语言 (VBScript 、 Jscript) 均在 WEB 服务器端执行,用户端的浏览器不需要能够执行这些脚本语言。

    5Active Server Pages 能与任何 ActiveX scripting 语言相容。除了可使用 VBScript或 JScript 语言来设计外,还通过 plug-in 的方式,使用由第三方所提供的其他脚本语言,譬如 REXX 、 Perl 、 Tcl 等。脚本引擎是处理脚本程序的 COM(Component Object Model) 物件。

    6可使用服务器端的脚本来产生客户端的脚本。

    77) ActiveX Server Components(ActiveX 服务器元件 ) 具有无限可扩充性。可以使用 Visual Basic 、 Java 、 Visual C++ 、 COBOL 等编程语言来编写你所需要的ActiveX Server Component 。

3.1.4  PHP

 ① 数据库连接PHP可以编译成具有与许多数据库相连接的函数。PHP与MySQL是现在绝佳的组合。你还可以自己编写外围的函数取间接存取数据库。通过这样的途径当你更换使用的数据库时,可以轻松地更改编码以适应这样的变。PHPLIB就是最常用的可以提供一般事务需要的一系列基库。但PHP提供的数据库接口支持彼此不统一,比如对Oracle, MySQL,Sybase的接口,彼此都不一样。这也是PHP的一个弱点。

    ② 面向对象编程

PHP提供了类和对象。基于web的编程工作非常需要面向对象编程能力。PHP支持构造器、提取类等。

3.1.5  ASP.NET

新的ASP.NET下部构造不只是 ASP 的一个简单变化. 在此引入收管代码(managed code)这样一个全新概念,它横贯整个视窗开发平台. 受管代码在NGWS Runtime下运行. NGWS Runtime是一个时间运行环境,它管理代码的执行,使程序设计更为简便.

1语言支持

ASP.NET支持多种语言,它的缺省语言将是:visual basic而不是vbscript,这意味着我们可以摆脱vbscript的语言限制,我们的代码将是编译后运行的(而不是原来的解释执行)。

2更好的代码控制

对于COM对象不再需要再在服务器上注册的这个功能我们是非常喜爱的。但是通过这种过程简化,你再也不能够在你的服务器上运行 另外一个DLL版本,并且代码相当保密,这意味着,如果没有正确的开发工具和源代码,很难改变代码。

3更好的升级能力

 此系统建成,本身有着一定的特性,以改进多处理器和串环境中的性能。例如,session state 能够通过单独的处理器来维持,在一个单独的机器上,甚至在数据库中允许交叉的服务器会话。

3.2 发展趋势与前景分析     

目前在国内JSP、PHP与ASP应用最为广泛。而ASP.NET由于是一种较新的技术,国内采用的较少。在国外,JSP已经是比较流行的一种技术,尤其是电子商务类的网站,多采用JSP。采用PHP的网站如新浪网(sina)、中国人(Chinaren)等,但由于PHP本身存在的一些缺点,使得它不适合应用于大型电子商务站点,而更适合一些小型的商业站点。首先,PHP缺乏规模支持。其次,缺乏多层结构支持。对于大负荷站点,解决方法只有一 个:分布计算。数据库、应用逻辑层、表示逻辑层彼此分开,而且同层也可以根据流量分开,组成二维阵列。而PHP则缺乏这种支持。还有上面提到过的一点,PHP提供的数据库接口支持不统一,这就使得它不适合运用在电子商务中。

ASP和JSP则没有以上缺陷,ASP可以通过Microsoft Windows的COM/DCOM获得ActiveX规模支持,通过DCOM和Transcation Server获得结构支持;JSP可以通过SUN Java的Java Class和EJB获得规模支持,通过EJB/CORBA以及众多厂商的Application Server获得结构支持。四者中,JSP、ASP。NET应该是未来发展的趋势。世界上一些大的电子商务解决方案提供商都采用JSP/Servlet。比较出名的如IBM的E-business,它的核心是采用JSP/Servlet的WebSphere。

     

第四章 电子邮件系统设计的相关原理

4.1 系统概述

从图1a 中可以看出,我们的邮件收发系统主要是完成邮件内容信息的接受、显示以及和SMTP、POP3 服务器的交互工作。图1b 给出了JavaMail 处理消息的流程。图1a 中的撰写邮件和发送给SMTP 服务器就分别对应JavaMail 中的生成Message 和Transport 一个Message,而显示邮件内容则是通过JavaMail 将从POP3 服务器上取得的Message 还原成邮件原文显示给用户。我们的WEBMAIL 一方面负责与POP3、SMTP 服务器收发Message,另一方面负责将要发出去的内容组成符合MIME 协议的Message 和将收到的Message 还原成为原始邮件内容显示给用户。对于如何用POP3、SMTP 协议通过服务器收发邮件很多文章都有介绍,而且借助JavaMail 很容易实现,本文将不在赘述。下面我们将重点讨论如何将一个Message 还原成邮件原文,进而了解MIME 协议和邮件中的编码问题。

4.2  电子邮件相关协议及其Java 解决

SMTP 协议:这是“简单邮件传输协议”,最初互联网上的电子邮件就是通过这个协议在不同主机上传播的。此协议只支持传输7bit 的字节流(每个字节的最高位将被强制转换为0),这就决定了SMTP 协议只能传输简单的ASCII 字符集的纯文本英文邮件。POP3 协议:虽然SMTP 协议支持了邮件的收发,但并不是每个人都能够有机器长时间做SMTP 服务器。这样就很多人共用一台SMTP 服务器,POP3 协议正是这种情况下支持用户从自己的SMTP 服务器上拿到自己邮件的协议。

MIME 协议:MIME 是“多用途互联网邮件扩展”的简称。由于SMTP 协议只能收发纯文本方式的英文邮件极大的影响了邮件的可用性,人们就用MIME 协议将复杂形式的邮件内容组织成为符合SMTP 协议要求的形式,然后通过已有的SMTP 协议进行邮件传输。要想正确还原从POP3 服务器上取得的Message,就要深入了解MIME协议内容。MIME 协议主要解决两个问题,一是如何将非ASCII 码的字节流(非英文文本或二进制文件)转换成为SMTP 服务器可以接受的7bit 字节流;二是如何在邮件中组织正文及附件等多个部分。此小节我们重点讨论如何组织正文及附件等多个部分。图2 就是一个MIME 邮件的例子,其中Header 部分的意义非常明显,这里不再介绍。Body 部分我们发现是以树形结构组织的,其中根节点类型说明(Content-Type)为“多部分混合”(multipart/mixed),并且各部分用边界(boundary)分隔。同样每个子节点也可以再有自己的子节点,从而形成了一个树形的文档结构,其中每一个叶节点就是一个文本正文、超文本正文或是邮件附件。用JavaMail 获取到一个Message 的输入流后,应该如何处理呢?图3 给出了JavaMail 中与MIME 邮件相关的类之间的关系。显然,邮件Body 部分中包含子节点的部分为Multipart 类的实例,而其中的叶节点就是BodyPart 类的实例。那么,我们首先用输入流构造一个Message 对象判断其是不是叶节点,然后分情况构造BodyPart或Multipart,如果是Multipart 则递归分解,直到分解到叶节点。图4 给出了对含有子节点的部分的解析代码。

当得到叶节点(文本正文、超文本正文或附件)后,就可以将其读出并存成文件,以便用户通过WEB 访问到该正文或附件。对于多部分的邮件,解析时应该保存其结构信息,这样JSP 就可以通过此信息组织呈现给用户的WEB 页面。比如有附件的邮件,就可以创建分FRAME 的网页,分开显示邮件正文和附件列表;而无附件的邮件就不必创建FRAME 网页。

4.3 字符编码及字符集转换问题

前面提到MIME要解决的另外一个问题就是将SMTP协议不支持的字节流转换成为SMTP 协议支持的字节流。比如我们要通过邮件传输一个附件文档,该附件文档就是一个8bit 字节流,如果简单的直接通过SMTP 发送,其最高位信息将被丢失。MIME规定可以用两种编码方式将8bit 的字节流编码成为低于8bit 的字节流,它们分别是BASE64 编码(BASE64 将8bit 字节流编码成6bit 字节流)和QP 编码。这两种编码方式同样应用在对中文的编码上。例如如果邮件中文题目叫做“CVS 介绍”,那么其编码后的形式可能为:    Subject:=?gb2312?B?Q1ZTLS3QpMX0LnBwdA==?=标题字符串以”=?”开始,以”?=”结束。”gb2312”表示字符串的字符集,而以”?”分隔的”B”就表示此字符串的编码方式为BASE64。我们处理此标题时就要先将BASE64编码的6bit 字节流转换为原来的8bit 字节流,再根据字符集”gb2312”转换为Java 中的String 类型。这里可以简单的使用JavaMail 提供的MimeUtility.decodeWord()静态方法将编码后的字符串解码。

第五章 使用JSP开发邮件系统

  在动态网站的制作中经常需要开发邮件系统,用户在访问网站时使用其邮件系统可以很方便的收发电子邮件。互联网上的许多门户网站都提供了自己的邮件系统,著名的如网易163电子邮局、搜狐的电子邮件系统,还有专门的电子邮件服务系统HOTMAIL等等,都为用户提供了强大的邮件服务功能。

   SUN公司发布的JAVAMAIL API提供了用于构建电子邮件系统的开发包,它实现了用于传输电子邮件的一些流行的协议,并且提供了方便的使用方法。在JSP中只需要调用JAVAMAIL开发包中的API就可以很方便的实现电子邮件的收发以及其他诸多功能。

5.1 搭建开发环境

    本节主要介绍JSP开发环境的搭建。首先介绍该邮件系统对运行环境的要求,接着讲述JSP开发。

5.1.1  该系统运行环境

为了保证系统运行的效率和可靠性,系统服务器端应具有较高的软硬件配置,客户端的要求不是很高。此应用程序可广泛运行于国际互联网即Internet,也可适用于内部的局域网。其运行要求如下:

(1)软件环境

客户端:  Windows95/98,Windows 2000/xp,Internet Explorer(IE)等

服务器端: Windows2000 Server (IIS)4.0及其以上版本,IE等

数据库:采用SQL,运行于服务器端。

(2)硬件环境

服务器 CPU:PIII 500以上 ,内存:256M以上

客户机 CPU:P200MMX以上,内存:32M以上 

5.1.2  安装和配置JDK

(1)JDK的安装

可先到http://java.sun.com/j2se/downloads.html下载j2sdk-1_4_1-win.exe

 自动解压后出现出现确认安装界面,在此界面中单击【NEXT】按钮。

 出现版权协议说明界面,单击【YES】按钮,接受版权协议后,选择安装路径,

C:\j2sdk1.4.2_05,然后单击【OK】按扭。

 出现安装组件的界面,直接单击【NEXT】按钮继续安装。

 选择一种浏览器,能在此浏览器中运行Applet,然后单击【NEXT】。

 对JDK进行按装,安装完毕,单击【Finish】结束安装。

(2)JDK的配置

   安装好JDK后,还需要在环境变量中进行相应的配置。如下:

 在桌面上单击“我的电脑”属性,依次选择【属性】/【高级】/【环境变量】选项。

② 新建一个环境变量,名为JAVA_HOME,值为C:\j2sdk1.4.2_05,如图5.1所示:

图5.1JDK配置

 单击【确定】按钮。

④ 用同样的方法设置其他环境变量:“Path=C:\j2sdk1.4.2_05\bin”;“CLASSPATH=.;”。

5.1.3  安装和配置Tomcat

    Tomcat服务器是当今使用广泛的Servlet/JSP服务器,它运行稳定,性能可靠,本节介绍Tomcat的安装、配置与使用,并做对应的测试。

(1)安装Tomcat

     可以从http://jakarta.apache.org/tomcat下载Tomcat 5.0 Servlet服务器,下载后单击安装。

     在弹出的窗口中单击【NEXT】按钮。

 出现授权界面,单击【I Agree】按钮。

 在弹出的界面中选择安装组件,可以选择“full“,然后单击【NEXT】按钮。

     选择安装目录然后单击【NEXT】按钮。

⑥ 配置Tomcat,默认断口8080,输入一个密码,本系统设置为“admin”。注意:必须记住这个密码。然后单击【NEXT】按钮,如图5.2所示:

图5.2 Tomcat密码设置

 选择JDK的安装位置,如C:\j2sdk1.4.2_05然后单击【NEXT】按钮。

 单击【Install】按钮。

⑨ 安装完成后单击【Finish】按钮。

(2)Tomcat的配置

安装好Tomcat后,还需要在环境变量中进行相应的配置。如下:

 在桌面上单击“我的电脑”属性,依次选择【属性】/【高级】/【环境变量】选。

 新建一个环境变量,名为CATALINA_HOME,值为C:\Program Files\Apache Software Foundation\Tomcat 5.3,如图7所示

图5.3Tomcat环境变量配置

 单击【确定】按钮,Tomcat配置完成。

5.1.4  测试是否安装配置成功

执行C:\Program Files\Apache Software Foundation\Tomcat 5.0\bin目录下的startup.bat,如果出现如图5.4所示,表示环境变量配置成功;

图5.4 Tomcat启动成功

这时候可以打开浏览器,在地址栏输入http://localhost:8080,便可以见到一网页样式页面。如不能启动Tomcat服务器或在浏览器不能获得相应的结果,请检查JDK的设置是否正确。

5.2  JavaMail简介

JavaMail API是一种可选的、能用于读取、编写和发送电子消息的包(标准扩展)。您可使用这种包创建邮件用户代理(Mail User Agent ,MUA) 类型的程序,它类似于Eudora、Pine及Microsoft Outlook这些邮件程序。其主要目的不是像发送邮件或其他邮件传输代理(Mail Transfer Agent,MTA)类型的程序那样用于传输、发送和转发消息。换句话说,用户可以与MUA类型的程序交互,以阅读和撰写电子邮件。MUA依靠MTA处理实际的发送任务。

JavaMail API的设计是,为收发信息提供与协议无关的访问。方式是把该API划分成两个部分:

该API的第一个部分是本课程的重点。基本上是如何发送和接收独立于提供程序/协议的消息。

第二个部分则使用特定的协议语言,如:SMTP、POP、IMAP和NNTP。如果要让JavaMail API与服务器通信,就需要为之提供协议。由于Sun公司对特定协议提供程序有充分的介绍,用户可以免费获取,所以本课程没有介绍创建特定协议提供程序的内容。

5.2.1  安装

目前有两种版本的JavaMail API最常用:1.2和1.1.3。本课程中的所有例子都适用于这两种版本。其中JavaMail API 1.2是最新的,而JavaMail API 1.1.3中包含了Java 2企业版(J2EE)平台1.2.1版,所以它仍然很常用。使用JavaMail API的版本会对您的下载和安装产生一些影响。这两种版本的JavaMail API都能与JDK 1.1.6、Java 2标准版(J2SE)平台1.2.x和1.3.x协同工作。

注意:在安装了Sun公司的JavaMail工具后,会在演示目录下看到许多示例程序。

安装JavaMail 1.2

要使用JavaMail 1.2 API,可以下载JavaMail 1.2工具,然后解压缩javamail-1_2.zip文件,并把mail.jar文件添加到典型安装路径下。JavaMail 1.2工具带有SMTP、IMAP4和POP3提供程序以及核心类。

安装完JavaMail 1.2后,再安装JavaBeans Activation Framework。

安装JavaMail 1.1.3

要使用JavaMail 1.1.3 API,可以下载JavaMail 1.1.3工具,然后解压缩javamail1_1_3.zip文件,并把mail.jar文件添加到典型安装路径下。JavaMail 1.1.3工具带有SMTP和IMAP4提供程序以及核心类。

如果您想用JavaMail 1.1.3访问POP服务器,需要下载并安装POP3提供程序。Sun公司拥有一个独立于 JavaMail 工具的提供程序。在下载并解压缩pop31_1_1.zip文件后,也还需要把pop3.jar添加到典型安装路径下。

安装完JavaMail 1.1.3后,再安装JavaBeans Activation Framework

安装JavaBeans Activation Framework

JavaMail API的所有版本都需要JavaBeans Activation Framework(JavaBeans激活框架),这种框架提供了对输入任意数据块的支持,并能相应地对其进行处理。看上去效果好像不太好,但该框架是在当今的许多浏览器和邮件工具中可以找到的基本MIME类型支持。下载该框架后,解压缩jaf1_0_1.zip文件,并将activation.jar文件添加到典型安装路径下。

对于JavaMail 1.2用户,现在应该把mail.jar和activation.jar文件添加到典型安装路径下。

对于JavaMail 1.1.3用户,现在应该把mail.jar、pop3.jar和activation.jar添加到典型安装路径下。如果您不打算使用POP3,就不需要把pop3.jar文件添加到典型安装路径下。

如果您不想更改安装路径环境变量,可以把JAR文件复制到Java运行时环境(JRE)目录下的lib/ext目录下。例如,对于J2SE 1.3版本,Windows平台上的默认目录应该是C:\jdk1.3\jre\lib\ext。

5.2.2  使用Java 2企业版

如果您使用的是J2EE,则在使用基本JavaMail API时,不需要做什么特殊的工作;JavaMail API带有J2EE类。只要确保j2ee.jar文件位于典型安装路径下,并完成了所有的设置工作。

对于J2EE 1.2.1,POP3提供程序是单独提供的,因此需要下载该提供程序,并按安装JavaMail 1.1.3的步骤,在J2EE 1.2.1中包含POP3提供程序。J2EE 1.3的用户会获得J2EE和POP3提供程序,因而不需要对POP3提供程序执行独立安装。使用这两种版本的J2EE用户,都不需要安装JavaBeans Activation Framework。

在开始深入研究JavaMail类之前,首先让用户浏览一下构成API的核心类:会话、消息、地址、验证程序、传输,存储和文件夹。所有这些类都可以在JavaMail API即javax.mail的顶层包中找到,尽管您将频繁地发现您自己使用的子类是在javax.mail.internet包中找到的。

Session类

Session类定义了一个基本的邮件会话。通过该会话可让别的工作顺利执行。Session对象利用java.util.Properties对象获取诸如邮件服务器、用户名、密码等信息,以及其他可在整个应用程序中共享的信息。

Session类的构造器是私有的。您可以获得一个可被getDefaultInstance()方法共享的单一的默认会话:

Properties props = new Properties();

// fill props with any information

Session session = Session.getDefaultInstance(props, null);

或者,您可以用getInstance()方法创建一个独特的会话:

Properties props = new Properties();

// fill props with any information

Session session = Session.getInstance(props, null);

这两种情形下的null参数都是一种Authenticator对象,它不是在此时使用的。详细信息请参阅其后的“Autherticator”一节。

在大多数情况下,使用共享会话就足够了,即使为多个用户邮箱处理邮件会话也是如此。您可以在通信过程的后面一步添加上用户名和密码的组合,并保持所有的一切是独立的。

Message类

一旦创建了自己的Session对象,就是该去创建要发送的消息的时候了。这时就要用到消息类型。作为一个抽象类,您必须操作一个子类,在大多数情况下,该子类是javax.mail.internet.MimeMessage。一个MimeMessage是一种理解MIME类型和报头(在不同的RFC文档中均有定义)的消息。消息的报头被严格限制成只能使用US-ASCII字符,尽管非ASCII字符可以被编码到某些报头字段中。

可以通过将Session对象传递给MimeMessage构造器的方法来创建消息:

MimeMessage message = new MimeMessage(session);

注意:还有其他的构造器,像用于创建消息的源于RFC822格式化的输入流的构造器。

一旦创建了消息,就可以设置其各个部分,如Message(消息)实现Part(部分)接口(以MimeMessage实现MimePart)。设置内容的基本机制是setContent()方法,它带有表示内容和MIME类型的参数:

message.setContent("Hello", "text/plain");

但是,如果正在使用 MimeMessage,并且您的消息是纯文本,那么您就可以使用setText()方法。该方法只需要一个表示实际内容的参数,默认的MIME类型为纯文本:

message.setText("Hello");

对于纯文本消息,setText()方法更常常被用来设置内容。要发送其他类型的消息,如HTML消息,就要使用setContent方法()。现在用的更多的是HTML消息。

要设置主题,可以使用setSubject()方法:

message.setSubject("First");

Address类

一旦创建了会话和消息,并为消息填充了内容,就需要用Address类为您的信件标上地址了。同Message类一样,Address类也是一种抽象类。您可以使用javax.mail.internet.InternetAddress类。

要创建只带有电子邮件地址的地址,可以把电子邮件地址传递给Address类的构造器:

Address address = new InternetAddress("president@whitehouse.gov");

如果想让一个名字出现在电子邮件地址后,也可以将其传递给构造器:

Address address = new InternetAddress("president@whitehouse.gov", "George Bush");

您要为消息的from(发送者)字段和to(接收者)字段创建地址对象。除非您的邮件服务器阻止这样做,否则要在发送的消息中注明该消息的发送者。

一旦创建好了地址,有两种方法可让您将地址与消息连接起来。为了鉴别发送者,您可以使用setFrom()和setReplyTo()方法。

message.setFrom(address)

如果您的消息需要显示多个地址来源,则可以使用addFrom()方法:

Address address[] = ...;

message.addFrom(address);

为了鉴别消息接收者,您可以使用addRecipient()方法。该方法除了需要一个地址参数外,需要一个Message.RecipientType属性(消息的接收类型)。

message.addRecipient(type, address)

地址的3种预定义类型如下:

Message.RecipientType.TO

Message.RecipientType.CC

Message.RecipientType.BCC

因此,如果一条消息将发送给副总统,同时还将发送该消息的副本给第一夫人,则采用下面的代码:

Address toAddress = new InternetAddress("vice.president@whitehouse.gov");

Address ccAddress = new InternetAddress("first.lady@whitehouse.gov");

message.addRecipient(Message.RecipientType.TO, toAddress);

message.addRecipient(Message.RecipientType.CC, ccAddress);

JavaMail API没有提供检查电子邮件地址有效性的机制。您可以自己编写支持扫描有效字符(在RFC 822文档中所定义的)的程序或检验MX(邮件交换)记录,这些都超越了JavaMail API的范围。

Authenticator类

与java.net类一样,JavaMail API可以利用Authenticator(验证程序)类通过用户名和密码来访问受保护的资源。对于JavaMail API来说,这种受保护的资源是指邮件服务器。JavaMail的Authenticator类可以在javax.mail包中找到,并有别于同名的java.net类。当JavaMail API在Java 1.1下工作时,JavaMail和java.net不会共享同一个Authenticator类名称,这是因为Java 1.1中不含有java.net。

要使用Authenticator类,您可以使用该抽象类的子类,并通过getPasswordAuthentication()方法返回一个PasswordAuthentication实例。在创建时,您必须用会话记录Authentication类。其后,当需要进行身份验证时,会通知您的Authenticator。会弹出一个窗口,或从一个配置文件(尽管不加密就不安全)中读取用户名和密码,并把它们作为一个PasswordAuthentication对象返回给调用程序。

Properties props = new Properties();

// fill props with any information

Authenticator auth = new MyAuthenticator();

Session session = Session.getDefaultInstance(props, auth);

Transport类

发送消息的最后一步操作是使用Transport类。该类使用特定于协议(通常是SMTP)的语言来发送消息。它是一个抽象类,其操作与Session类有些相似。您可以通过只调用静态的send()方法来使用该类的默认版本:

Transport.send(message);

或者,您可以从用于您的协议的会话中获取一个特定的实例,然后传递用户名和密码(不必要时可以为空)并发送消息,最后关闭连接:

message.saveChanges(); // implicit with send()

Transport transport = session.getTransport("smtp");

transport.connect(host, username, password);

transport.sendMessage(message, message.getAllRecipients());

transport.close();

当您需要发送多个消息时,建议采用后一种方法,因为它将保持消息间活动服务器的连接。而基本的send()机制会为每一个方法调用都建立一条独立的连接。

注意:要查看经过邮件服务器邮件命令,可以用session.setDebug(true)方法设置调试标志。

Store和Folder类

使用Session类来获取消息,开始时与发送消息很相似。但是,在获取会话后,很有可能使用用户名和密码或Authenticator类来连接Store类。与Transport类一样,您要告诉Store类将使用什么协议:

// Store store = session.getStore("imap");

Store store = session.getStore("pop3");

store.connect(host, username, password);

在连接Store类后,就可以获取一个Folder类,在读取其中的消息前必须先打开该类。

Folder folder = store.getFolder("INBOX");

folder.open(Folder.READ_ONLY);

Message message[] = folder.getMessages();

对于POP3协议,惟一可用的文件夹是INBOX。如果使用的是IMAP协议,则可以使用其他的文件夹。

注意:Sun公司的提供程序本来想提供方便。而Message message[]=folder.getMessages();这条语句却是一种从服务器逐条读取消息的缓慢操作,所以仅当您确实需要获取消息部分(该内容是所检索消息的内容)时可以使用这条语句。

一旦读取消息,就可以使用getContent()方法获取其内容,或使用writeTo()方法将其内容写到一个流中。getContent()方法只获取消息内容,而writeTo()方法则还会输出报头。

System.out.println(((MimeMessage)message).getContent());

一旦您阅读完邮件,就可以关闭对文件夹和存储的连接。

folder.close(aBoolean);

store.close();

传递给文件夹的close()方法的布尔变量指定了是否通过清除已删除的消息来更新文件夹。

实际上,理解使用这7个类的方式,是使用JavaMail API处理几乎所有事情所需要的全部内容。用这7个类以外的方式构建的JavaMail API,其大多数功能都是以几乎完全相同或特定的方式来执行任务的,就好像内容是附件。特定的任务,如:搜索、隔离等将在后面进行介绍。

使用JavaMail API

您已经看到了如何操作JavaMail API的核心部分。在下面几节中,您将学习如何连接几个部分以执行特定的任务。

发送消息

发送电子邮件消息涉及到获取会话、创建和填充消息并发送消息这些操作。您可以在获取Session时,通过为要传递的Properties对象设置mail.smtp.host属性来指定您的SMTP服务器。

String host = ...;

String from = ...;

String to = ...;

// Get system properties

Properties props = System.getProperties();

// Setup mail server

props.put("mail.smtp.host", host);

// Get session

Session session = Session.getDefaultInstance(props, null);

// Define message

MimeMessage message = new MimeMessage(session);

message.setFrom(new InternetAddress(from));

message.addRecipient(Message.RecipientType.TO,

new InternetAddress(to));

message.setSubject("Hello JavaMail");

message.setText("Welcome to JavaMail");

// Send message

Transport.send(message);

您应该在try-catch块中编写代码,以在创建消息并发送它时可以抛出一个异常。

发送您的第一个消息

获取消息

对于阅读邮件来说,首先您要获取一个会话,然后获取并连接到一个相应的用于您的收件箱存储上,接着打开相应的文件夹,再获取消息。同时,不要忘记了操作完成后关闭连接。

String host = ...;

String username = ...;

String password = ...;

// Create empty properties

Properties props = new Properties();

// Get session

Session session = Session.getDefaultInstance(props, null);

// Get the store

Store store = session.getStore("pop3");

store.connect(host, username, password);

// Get folder

Folder folder = store.getFolder("INBOX");

folder.open(Folder.READ_ONLY);

// Get directory

Message message[] = folder.getMessages();

for (int i=0, n=message.length; i<n; i++) {

System.out.println(i + ": " + message[i].getFrom()[0]

+ "\t" + message[i].getSubject());

}

// Close connection

folder.close(false);

store.close();

每一条消息执行何种操作取决于自己决定。上面的代码块只是显示了消息的发送者和主题。从技术上讲,发送者地址列表可以为空,此时getFrom()[0]调用会抛出一个异常。

为了显示整条消息,您可以提示用户在看完消息的发送者和主题字段后,如果想看到消息的内容,可以再调用消息的writeTo()方法。

BufferedReader reader = new BufferedReader (

new InputStreamReader(System.in));

// Get directory

Message message[] = folder.getMessages();

for (int i=0, n=message.length; i<n; i++) {

System.out.println(i + ": " + message[i].getFrom()[0]

+ "\t" + message[i].getSubject());

System.out.println("Do you want to read message? " +

"[YES to read/QUIT to end]");

String line = reader.readLine();

if ("YES".equals(line)) {

message[i].writeTo(System.out);

} else if ("QUIT".equals(line)) {

break;

}

}

删除消息和标志

删除消息涉及到操作与消息关联的标志。对不同的状态有不同的标志,有些标志是系统定义的,有些则是由用户定义的。预定义的标志都是在内部类Flags.Flag中定义的,如下所示:

Flags.Flag.ANSWERED

Flags.Flag.DELETED

Flags.Flag.DRAFT

Flags.Flag.FLAGGED

Flags.Flag.RECENT

Flags.Flag.SEEN

Flags.Flag.USER

仅仅因为标志存在,并不表示标志为所有的邮件服务器/提供程序所支持。例如,除了删除消息外,POP协议对它们都不支持。检查新邮件不是POP的任务,但它已内置到邮件客户程序中。要搞清楚什么标志受到支持,可以使用getPermanentFlags()方法来询问文件夹。

要删除消息,需要为消息设置DELETE标志:

message.setFlag(Flags.Flag.DELETED, true);

第一次以READ_WRITE(读-写)模式打开文件夹:

folder.open(Folder.READ_WRITE);

然后,处理完了所有的消息,请关闭文件夹,并传递true值以擦去删除的消息。

folder.close(true);

用户可使用Folder类的expunge()方法来删除消息。但是,该方法对Sun公司的POP3提供程序不起作用。其他提供程序或许能也或许不能实现其功能。它更有可能适用于IMAP提供程序。由于POP只支持对收件箱的简单访问,使用Sun公司的提供程序时,您将不得不关闭文件夹以删除消息。

要移去标志,只需传递一个false值给setFlag()方法。要看看是否设置了某个标志,可以使用isSet()进行检查。

自我验证

先前学到的是使用Authenticator类,以在需要时提示输入用户名和密码,而不是以字符串的形式传入它们。这里,您将真正看到如何更加充分地使用验证。

不需使用主机、用户名和密码连接到Store,您可以配置Properties带有主机,并告诉Session关于您自定义的Authenticator实例,如下所示:

// Setup properties

Properties props = System.getProperties();

props.put("mail.pop3.host", host);

// Setup authentication, get session

Authenticator auth = new PopupAuthenticator();

Session session = Session.getDefaultInstance(props, auth);

// Get the store

Store store = session.getStore("pop3");

store.connect();

然后您可以使用Authenticator类的子类,并通过getPasswordAuthentication()方法返回一个PasswordAuthentication对象。下面是这种实现的一个例子,其中一个字段同时适用于两部分内容。它不是一个Project Swing指南,只是在一个字段中输入了两部分内容,它们是用逗号隔开的。

import javax.mail.*;

import javax.swing.*;

import java.util.*;

public class PopupAuthenticator extends Authenticator {

public PasswordAuthentication getPasswordAuthentication() {

String username, password;

String result = JOptionPane.showInputDialog(

"Enter 'username,password'");

StringTokenizer st = new StringTokenizer(result, ",");

username = st.nextToken();

password = st.nextToken();

return new PasswordAuthentication(username, password);

}

}

由于PopupAuthenticator依赖于Swing,因而将会启动用于AWT的事件处理线程。这在本质上要求您在代码中添加一个对System.exit()的调用,以终止程序的执行。

回复消息

Message类包含一个reply()方法,以用正确的接收者和主题(添加“Re::”,如果没有的话)配置一条新消息。该方法不会为消息添加任何内容,只是为新的接收者复制发送者或回复到的报头。该方法使用一个布尔型参数,提示是否只回复给发送者(false)或回复给所有人(true)。

MimeMessage reply = (MimeMessage)message.reply(false);

reply.setFrom(new InternetAddress("president@whitehouse.gov"));

reply.setText("Thanks");

Transport.send(reply);

在发送消息时要配置回复到地址,可使用setReplyTo()方法。

转发消息

转发消息涉及的内容要稍微多一点,没有一个专门用于转发消息的方法,您可以通过处理组成消息的各个部分来创建要转发的消息。

一条邮件消息可由多个部分组成,每一部分是一个BodyPart(报文部分),或更特殊一点,在操作MIME消息时则是MimeBodyPart。不同的报文部分组合到一个称为Multipart的容器中,或者又更特殊一点,是一个MimeMultipart容器。要转发消息,您要创建一个用于消息文本的部分,和用于要转发的消息的第二个部分,并将这两个部分组合成一个multipart(多个部分)。然后您可以把这个multipart添加到一个合适的注明地址的消息中并发送它。

这就是转发消息的本质。要把一条消息的内容复制给另一条消息,只需通过它的DataHandler类复制即可,它是出自于JavaBeans Activation Framework的一个类。

// Create the message to forward

Message forward = new MimeMessage(session);

// Fill in header

forward.setSubject("Fwd: " + message.getSubject());

forward.setFrom(new InternetAddress(from));

forward.addRecipient(Message.RecipientType.TO,

new InternetAddress(to));

// Create your new message part

BodyPart messageBodyPart = new MimeBodyPart();

messageBodyPart.setText(

"Here you go with the original message:\n\n");

// Create a multi-part to combine the parts

Multipart multipart = new MimeMultipart();

multipart.addBodyPart(messageBodyPart);

// Create and fill part for the forwarded content

messageBodyPart = new MimeBodyPart();

messageBodyPart.setDataHandler(message.getDataHandler());

// Add part to multi part

multipart.addBodyPart(messageBodyPart);

// Associate multi-part with message

forward.setContent(multipart);

// Send message

Transport.send(forward);

操作附件

附件是与邮件消息关联的资源,通常保存在消息之外,如:一个文本文件,电子表格或图片。对于像Eudora和Pine之类的常用邮件程序,您可以通过JavaMail API把资源附加到邮件消息上,并在您接收消息时获取附件。

发送附件

发送附件与转发消息非常相似,您要创建组成完整消息的各个部分。在创建好第一个部分即消息文本之后,您添加的用DataHandler类处理的其他部分就是您的附件,而不是转发消息中的共享处理程序。当您从一个文件读取附件时,附件的数据资源是FileDataSource;从URL读取时,则是URLDataSource。一旦您有了自己的DataSource,在将其通过setDataHandler()方法最终附加到BodyPart上之前,只需将其传递给DataHandler类的构造器即可。假定您想保留附件的原始文件名,要做的最后一件事就是用BodyPart类的setFileName()方法设置与附件关联的文件名。所有这些操作如下所示:

// Define message

Message message = new MimeMessage(session);

message.setFrom(new InternetAddress(from));

message.addRecipient(Message.RecipientType.TO,

new InternetAddress(to));

message.setSubject("Hello JavaMail Attachment");

// Create the message part

BodyPart messageBodyPart = new MimeBodyPart();

// Fill the message

messageBodyPart.setText("Pardon Ideas");

Multipart multipart = new MimeMultipart();

multipart.addBodyPart(messageBodyPart);

// Part two is attachment

messageBodyPart = new MimeBodyPart();

DataSource source = new FileDataSource(filename);

messageBodyPart.setDataHandler(new DataHandler(source));

messageBodyPart.setFileName(filename);

multipart.addBodyPart(messageBodyPart);

// Put parts in message

message.setContent(multipart);

// Send the message

Transport.send(message);

在消息中包含附件时,如果您的程序是一个servlet,您的用户就必须上传附件,并告诉您要把消息发送到什么位置。上传的每一个文件都可以用一个表单来处理,该表单是以multipart/表单数据(form-data)来编码的。

<FORM ENCTYPE="multipart/form-data"

method=post action="/myservlet">

<INPUT TYPE="file" NAME="thefile">

<INPUT TYPE="submit" VALUE="Upload">

</FORM>

注意:消息的大小要受到您的SMTP服务器的限制,而不是由JavaMail API限制的。如果出现了问题,可以通过设置ms和mx参数来考虑增加Java堆区的空间尺寸。

获取附件

从消息中取出附件比发送附件涉及的操作要稍微多一点,而MIME没有简单的附件概念。当消息带有附件时,消息的内容就是一个Multipart对象。然后需要处理各个部分,以获取主要内容和附件。通过part.getDisposition()方法标记上Part.ATTACHMENT配置的部分显然就是附件。同时,附件也可以不带有配置(和非文本MIME类型)或Part.INLINE配置。当配置是Part.ATTACHMENT或Part.INLINE时,您可以脱离该消息部分的内容将其保存起来。只需通过getFileName()方法获取原始文件名,并通过getInputStream()方法获取输入流即可。

Multipart mp = (Multipart)message.getContent();

for (int i=0, n=multipart.getCount(); i<n; i++) {

Part part = multipart.getBodyPart(i));

String disposition = part.getDisposition();

if ((disposition != null) &&

((disposition.equals(Part.ATTACHMENT) ||

(disposition.equals(Part.INLINE))) {

saveFile(part.getFileName(), part.getInputStream());

}

}

saveFile()方法只用于根据文件名创建一个文件,从输入流中读取字节,并将它们写入一个文件中去。如果文件已存在,将在文件名后添加一个编号,直到找到一个不存在的文件为止。

// from saveFile()

File file = new File(filename);

for (int i=0; file.exists(); i++) {

file = new File(filename+i);

}

上面的代码介绍了消息的各个部分被标上相应的标志的一个最简单的例子。要想包含所有的情况,还要对disposition值为null及消息部分为MIME类型的情况作相应处理。

if (disposition == null) {

// Check if plain

MimeBodyPart mbp = (MimeBodyPart)part;

if (mbp.isMimeType("text/plain")) {

// Handle plain

} else {

// Special non-attachment cases here of image/gif, text/html, ...

}

...

}

处理HTML消息

发送基于HTML的消息比发送纯文本消息要稍微复杂一点,尽管它不需要做大量的工作。它全部取决于您特定的需求。

发送HTML消息

如果您所要做的全部工作是发送一个等价的HTML文件作为消息,并让邮件阅读者忧心于取出任何嵌入的图片或相关片段,那么就可以使用消息的setContent()方法,以字符串形式传递消息内容,并把内容类型设置为text/html。

String htmlText = "<H1>Hello</H1>" +

"<img src=\"http://www.jguru.com/images/logo.gif\">";

message.setContent(htmlText, "text/html"));

在接收端,如果您用JavaMail API获取消息,在该API中没有内置任何用于以HTML格式显示消息的功能。JavaMail API只以字节流的形式来查看消息。要以HTML格式显示消息,您必须使用Swing JeditorPane或某些第3方HTML阅读器组件。

if (message.getContentType().equals("text/html")) {

String content = (String)message.getContent();

JFrame frame = new JFrame();

JEditorPane text = new JEditorPane("text/html", content);

text.setEditable(false);

JScrollPane pane = new JScrollPane(text);

frame.getContentPane().add(pane);

frame.setSize(300, 300);

frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

frame.show();

}

在消息中包含图片

另一方面,如果您的HTML消息中嵌入了作为消息一部分的图片,并且您想保持消息内容的完整,就必须把图片看作附件,并用特殊的通信标识符URL引用该图片,该通信标识符引用的是图片附件的内容ID报文。

嵌入图片的处理与附加一个文件到消息上非常相似,惟一的不同之处在于:您必须区分MimeMultipart中,哪些部分是在构造器(或通过setSubType()方法)通过设置其子类型而使之相关的,以及将图片的内容ID报头设置成任意字符串,它将在img标记中用作图片的源路径。下面显示了一个完整的示例:

String file = ...;

// Create the message

Message message = new MimeMessage(session);

// Fill its headers

message.setSubject("Embedded Image");

message.setFrom(new InternetAddress(from));

message.addRecipient(Message.RecipientType.TO,

new InternetAddress(to));

// Create your new message part

BodyPart messageBodyPart = new MimeBodyPart();

String htmlText = "<H1>Hello</H1>" +

"<img src=\"cid:memememe\">";

messageBodyPart.setContent(htmlText, "text/html");

// Create a related multi-part to combine the parts

MimeMultipart multipart = new MimeMultipart("related");

multipart.addBodyPart(messageBodyPart);

// Create part for the image

messageBodyPart = new MimeBodyPart();

// Fetch the image and associate to part

DataSource fds = new FileDataSource(file);

messageBodyPart.setDataHandler(new DataHandler(fds));

messageBodyPart.setHeader("Content-ID","memememe");

// Add part to multi-part

multipart.addBodyPart(messageBodyPart);

// Associate multi-part with message

message.setContent(multipart);

用SearchTerm搜索

JavaMail API包含一种可用于创建SearchTerm(搜索条件)的筛选机制,它可以在javax.mail.search包中找到。一旦创建了SearchTerm,您就可以询问某个文件夹匹配的消息,并检索出消息对象数组:

SearchTerm st = ...;

Message[] msgs = folder.search(st);

有22种不同的类可用于帮助创建搜索条件。

AND条件(AndTerm类)

OR条件(OrTerm类)

NOT条件(NotTerm类)

SENT DATE条件(SentDateTerm类)

CONTENT条件(BodyTerm类)

HEADER条件(FromTerm / FromStringTerm, RecipientTerm / RecipientStringTerm, SubjectTerm, etc.)

本质上,您可以为匹配的消息创建一个逻辑表达式,然后进行搜索。例如,下面显示了一条消息的条件搜索示例,该消息带有(部分带有)一个ADV主题字符串,其发送者字段为friend@public.com。您可能考虑定期运行该查询,并自动删除任何返回的消息。

SearchTerm st =

new OrTerm(

new SubjectTerm("ADV:"),

new FromStringTerm("friend@public.com"));

Message[] msgs = folder.search(st);

5.3  使用JSP发送邮件

5.3.1  E-MAIL常识

    要开发电子邮件系统,对E-MAIL常识的了解是必不可少的。图5展示了一个典型的E-MAIL传递过程:如图5.3.1所示:

                                     图5.3.1

     从图中可以看到一个典型的E-MAIL传递过程是这样的:发送者创建一个E-MAIL并把它传递给邮件服务器,邮件服务器使用简单邮件传输协议(SMTP)通过INTERNET将邮件发送到另一个邮件服务器上的收件人邮箱里。然后接收者使用一种检索协议,比如邮箱协议(POP3)或网络消息访问协议(IMAP),来从他们的邮件服务器上收取E-MAIL。

   常用的几种E-MAIL协议有以下这些:

SMTP

简单邮件传输协议(SMTP)是用于传送电子邮件的机制。在JavaMail API环境中,您的基于JavaMail的程序将与您公司或Internet服务提供商(ISP)的SMTP服务器通信。该SMTP服务器将会把消息转发给用作接收消息的SMTP服务器,最后用户可通过POP或IMAP协议获取该消息。由于支持身份验证,所以不需要SMTP服务器是一种开放的转发器,但需要确保SMTP服务器配置正确。JavaMail API中没有集成用于处理诸如配置服务器以转发消息或添加/删除电子邮件帐户这一类任务的功能。

POP

POP的含义是邮局协议,当前的版本为3,也称作POP3,该协议是在RFC 1939中定义的。POP是Internet上的大多数人用来接收邮件的机制。它为每个用户的每个邮箱定义支持,这是它所做的全部工作,也是大多数问题的根源。在使用POP协议时,人们熟悉的很多功能,如查看收到了多少新邮件消息的功能,POP根本不支持。这些功能都内置到诸如Eudora或Microsoft Outlook之类的邮件程序中,能为您记住接收的上一封邮件,以及计算有多少新邮件这类信息。因此,使用JavaMail API时,如果想获取这类信息,将需要由自己进行计算。

IMAP

IMAP是用于接收消息的更加高级的协议,它是在RFC 2060中定义的。IMAP的含义是“Internet消息访问协议”,当前版本是第4版,也称作IMAP4。使用IMAP时,您的邮件服务器必须支持该协议。您不能只是简单地把程序转变为支持IMAP,而不是支持POP,就指望能支持IMAP中的一切。假定您的邮件服务器支持IMAP,那么基于JavaMail的程序就可利用在服务器上拥有多个文件夹的用户,并且这些文件夹可以被多个用户共享的功能。由于IMAP协议具有更高级的功能,您也许会想IMAP应该被每一个人使用,但事实不是这样。因为IMAP会加重邮件服务器的负荷,它需要服务器接收新消息,发送消息给请求的用户,并在多个文件夹中为每个用户维护这些消息。而这要集中备份,因而长期下去用户的文件夹会变得越来越大,当磁盘空间用光了时,每个人都会遭受损失。而使用POP协议时,已保存消息可以解除服务器的重负。

MIME

MIME的含义是“多用途的网际邮件扩充协议”。它不是一种邮件传输协议,相反,它定义传输的内容:消息的格式、附件等。许多文档都定义了MIME协议,包含:RFC 822、RFC 2045、RFC 2046和RFC 2047。作为JavaMail API的用户,一般不需要担心这些格式。但是,这些格式确实存在,并为您的程序所用。

NNP和其他协议

由于JavaMail API分开了提供程序和其他部分,所以您可以轻松地为附加协议添加支持。Sun公司提供第3方提供程序清单,这些提供程序要利用 Sun公司不支持的少见的协议。在这份清单中,您将会看到对NNTP(网络新闻传输协议)[新闻组]、S/MIME(安全多用途的网际邮件扩充协议)及其他协议的提供支持的第3方提供程序。

了解了以上信息我们就可以用JSP来开发邮件系统了。

5.3.2   发送普通文本格式的E-MAIL

要发送E-MAIL需要先给用户提供一个用于发送E-MAIL的HTML表单,表单中填写发件人的地址、收件人的地址、E-MAIL的标题和内容。程序在附录中(程序一)

程序运行如下图5.3.2所示:

                                  图5.3.2

在填写完此表单之后,其内容被提交到用于处理E-MAIL发送的JSP页面中去,程序如附录中JSP程序2所示。 

通常用于发送E-MAIL的SMTP邮件服务器需要权限认证,只允许合法的用户通过它发送E-MAIL,发件人必须填写在此SMTP邮件服务器上申请E-MAIL地址时注册的用户名和密码以供验证合法性,这也是一种出于安全的考虑。

在上面的JSP程序中,用Properties对象的Put方法设置了SMTP邮件服务器需要进行权限的人证:

props.put(“mail.smtp.auth”, “ture”);

程序中还用到了Session对象的setDebug方法设置输出发送E-MAIL时的调试信息:

Sendsession.setDebug(true);

在运行此JSP程序时会在Tomcat服务器上看到SMTP邮件服务器交互过程中输出信息。这对我们调试程序、了解E-MAIL发送过程是很有必要的

另外,在设置完了E-MAIL的所有信息之后,用Message对象的saveChanges方法将E-MAIL的信息保存起来:

message.saveChanges();

然后用Session对象创建Transport对象,并使用发件人的用户名和密码连接到SMTP服务器上去:

transport.connect(“smtp.163.com”, “username”, “password”);

最后用sendMessage方法将邮件发给所有已设置好的收件人的地址:

transport.sendMessage(message,message.getAllRecipients());

注意:使用JAVAMAIL发送的E-MAIL存在中文问题,如不纠正则接收到的E-MAIL将是乱码。为了解决发送邮件的中文问题,可以像上面JSP程序中使用“new String(request.getParameter(“text”). GetBytes(“ISO8859_1”), “GBK”)”将发送的文字编码转换为中文编码,这样接收到的E-MAIL就可以正常显示中文了。

好了,现在可以来发送E-MAIL了。在图10中填入相应的内容就可以发送邮件了如发送成功就会提示“发送成功”。

5.3.3 发送带附件的E-MAIL

通常我们在发送邮件的时候往往还带有附件,带有附件的E-MAIL实际上是一个多部分的MIME(多用途的Internet邮件扩展)风格的信息,它的前一部分是E-MAIL的正文,其他部分就是附件。

发送带附件的E-MAIL时,所要填写的表单只需要在程序1的基础上填加一个选择附件文件的选项按钮,程序如附录中程序3所示。

在来编写能发送带附件的E-MAIL的JSP程序。

程序如附录中JSP程序4所示。

现在可以尝试发送带附件的E-MAIL了。

5.4  使用JSP接收E-MAIL

通常我们在收取E-MAIL的时候,先要让用户名和密码通过邮件服务器的验证,然后进入一个显示当前所有E-MAIL列表的页面,点击其中某个E-MAIL的连接即可查看到此E-MAIL的正文内容了。

JAVAMAIL很好地支持了对E-MAIL的接受操作,这只需要相关的几个类就能实现对E-MAIL的接收操作。进入页面如下图5.4:

                        图5.4

5.4.1  显示所有E-MAIL列表

接收邮件的表单程序如下(程序5):

<html>

<head>

<title>登陆邮件服务器</title>   

</head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<body>

<center><h2>

  登陆邮件服务器

</h2></center>

<br>

<form Name="receform" action="09_09.jsp" method="post">   

<table width="70%" border="0" align="center">

  <tr>

    <td width="30%">邮件服务器:</td>

    <td width="70%" align="center">

       <input name="host">

    </td>

  </tr>

  <tr>

    <td width="30%">用户名:</td>

    <td width="70%" align="center">

      <input name="user">

    </td>

  </tr>

  <tr>

    <td width="30%">密码:</td>

    <td width="70%" align="center">

      <input type="password" name="password">

    </td>

  </tr>

  <tr>

    <td colspan=2 align="center">

      <br><br><a href="javascript:receform.submit();">进入我的邮箱</a>

    </td>

  </tr>

</table>

</form>

</body>

</html>

运行这个HTML表单效果如图5.4.1所示:

                        图5.4.1

在填写完此表单后,将其内容提交到程序6中。这个JSP程序(程序6)页面用来接收新到的E-MAIL,并列出当前所有E-MAIL的列表。JSP程序6如下:

<html>

<head>

<title>显示所有e-mail列表</title>   

</head>

<%@ page contentType="text/html;charset=GB2312"%>

<%@ page import="javax.mail.*,java.util.*"%>

<body>

<center><h2>

  显示所有e-mail列表

</h2></center>

<%

 try{

   //获得一个session对象,并设置其属性为true

   Properties props=new Properties();

   Session recesession=Session.getInstance(props,null);

   recesession.setDebug(true);

   //创建一个Store对象,并根据得到的三个参数连接到邮件服务器中的用户邮箱  

   Store store=recesession.getStore("pop3");

   String host=request.getParameter("host");

   String user=request.getParameter("user");

   String password=request.getParameter("password");

   store.connect(host,user,password);

   //打开收件箱

   Folder inbox=store.getFolder("INBOX");

   inbox.open(Folder.READ_ONLY);

   //得到邮箱中的e-mail总数

   int count=inbox.getMessageCount();

%>

<h3>收件箱中有<%=count%>封e-mail:</h3>

<%   

   //循环显示所有的e-mail的标题

   for(int i=1;i<=count;i++)

   {

      Message message=inbox.getMessage(i);

      //如果不是待删除的e-mail就显示出来

      if(!message.isSet(Flags.Flag.DELETED))

      {

         String title=message.getSubject();

%>

<p>

(<%=i%>)   

标题:

<a href="09_08.jsp?msg=<%=i%>&host=<%=host%>&user=<%=user%>&password=<%=password%>"><%=title%></a>

</p>   

<%

      }

   }

   //关闭收件箱和到邮件服务器的连接

   inbox.close(true);

   store.close();

 }catch(MessagingException m)

 {

    out.println(m.toString());

 }

%>   

</body>

</html>

在图11的表单中,邮件服务器一栏填写“pop.163.com”表示使用网易163邮箱中接收E-MAIL,然后分别在用户名和密码栏目中填写进入163邮箱需要验证的用户信息。单击 “进入我的邮箱”的链接,就会看到邮箱中的所有E-MAIL列表了。

5.4.2  接收普通文本格式的E-MAIL

接收、检索E-Mail的整个流程如图5.4.2所示:

                                 图5.4.2

程序如下(JSP程序7):

<html>

<head>

<title>显示普通文本格式e-mail的详细信息</title>

</head>

<%@ page contentType="text/html;charset=GB2312"%>

<%@ page import="javax.mail.*,java.util.*,java.io.*"%>

<body>

<center><h2>

  显示e-mail的详细信息

</h2></center>

<%

  //得到要察看的e-mail的编号msg,即要看第几封e-mail

  String msg=request.getParameter("msg");

  //得到邮件服务器要验证的参数

  String host=request.getParameter("host");

  String user=request.getParameter("user");

  String password=request.getParameter("password");

  try{

     //获得一个session对象,并设置其属性为true

     Properties props=new Properties();

     Session recesession=Session.getInstance(props,null);

     recesession.setDebug(true);

     //创建一个Store对象,并根据得到的三个参数连接到邮件服务器中的用户邮箱

     Store store=recesession.getStore("pop3");

     store.connect(host,user,password);

     //打开收件箱

     Folder inbox=store.getFolder("INBOX");

     inbox.open(Folder.READ_ONLY);

     //根据msg参数得到该e-mail

     int imsg=Integer.parseInt(msg);

     Message message=inbox.getMessage(imsg);

     Address[] address;

%>

<table width=85% align="center">

  <tr>

    <td>发件人:</td>

    <td>    

    <%

       //得到发件人的地址

       address=message.getFrom();

       if(address!=null)

          for(int i=0;i<address.length;i++)

            out.print(address[i]+"  ");

       else

          out.println("无");

    %>

    </td>

  </tr>

  <tr>

    <td>发送时间:</td>

    <td>    

    <%

       //得到e-mail发出的时间

       Date sentdate=message.getSentDate();

       if(address!=null)

          out.print(sentdate.toString());

       else

          out.println("无");

    %>

    </td>

  </tr>

  <tr>

    <td>收件人:</td>

    <td>

    <%

       //得到收件人的地址列表

       address=message.getRecipients(Message.RecipientType.TO);

       if(address!=null)

          for(int i=0;i<address.length;i++)

            out.print(address[i]+"  ");

       else

          out.println("无");

    %>

    </td>

  </tr>

  <tr>

    <td>抄送:</td>

    <td>

    <%

       //得到抄送人的地址

       address=message.getRecipients(Message.RecipientType.CC);

       if(address!=null)

          for(int i=0;i<address.length;i++) {

             out.print(address[i]+"  ");

          }

       else

          out.println("无");

    %>

    </td>

  </tr>

  <tr>

    <td>标题:</td>

    <td><%=message.getSubject()%></td>

  </tr>

  <tr>

    <td colspan=2>

    <br>   

    <%

       //如果邮件是普通文本形式,则显示其详细内容

       if(message.isMimeType("text/plain"))         

          out.print(message.getContent());

    %>

    </td>

  </tr>

</table>

<%

   //关闭收件箱和到邮件服务器的连接

   inbox.close(true);

   store.close();

 }catch(MessagingException m)

 {

    out.println(m.toString());

 }

%>

<p><center>

<a href="09_06.jsp?host=<%=host%>&user=<%=user%>&password=<%=password%>">返回收件箱<a>

</center></p>

</body>

</html>

5.4.3  收带附件的E-MAIL

接收带附件的E-MAIL的过程是这样的,JSP程序如下(JSP程序8):

<html>

<head>

<title>显示e-mail的详细信息</title>

</head>

<%@ page contentType="text/html;charset=GB2312"%>

<%@ page import="javax.mail.*,java.util.*,java.io.*"%>

<body>

<center><h2>

  接收带附件的e-mail

</h2></center>

<%

  //得到要察看的e-mail的编号msg,即要看第几封e-mail

  String msg=request.getParameter("msg");

  //得到邮件服务器要验证的参数

  String host=request.getParameter("host");

  String user=request.getParameter("user");

  String password=request.getParameter("password");

  try{

     //获得一个session对象,并设置其属性为true

     Properties props=new Properties();

     Session recesession=Session.getInstance(props,null);

     recesession.setDebug(true);

     //创建一个Store对象,并根据得到的三个参数连接到邮件服务器中的用户邮箱

     Store store=recesession.getStore("pop3");

     store.connect(host,user,password);

     //打开收件箱

     Folder inbox=store.getFolder("INBOX");

     inbox.open(Folder.READ_ONLY);

     //根据msg参数得到该e-mail

     int imsg=Integer.parseInt(msg);

     Message message=inbox.getMessage(imsg);

     Address[] address;

%>

<table width=85% align="center">

  <tr>

    <td>发件人:</td>

    <td>    

    <%

       //得到发件人的地址

       address=message.getFrom();

       if(address!=null)

          for(int i=0;i<address.length;i++)

            out.print(address[i]+"  ");

       else

          out.println("无");

    %>

    </td>

  </tr>

  <tr>

    <td>发送时间:</td>

    <td>    

    <%

       //得到e-mail发出的时间

       Date sentdate=message.getSentDate();

       if(address!=null)

          out.print(sentdate.toString());

       else

          out.println("无");

    %>

    </td>

  </tr>

  <tr>

    <td>收件人:</td>

    <td>

    <%

       //得到收件人的地址列表

       address=message.getRecipients(Message.RecipientType.TO);

       if(address!=null)

          for(int i=0;i<address.length;i++)

            out.print(address[i]+"  ");

       else

          out.println("无");

    %>

    </td>

  </tr>

  <tr>

    <td>抄送:</td>

    <td>

    <%

       //得到抄送人的地址

       address=message.getRecipients(Message.RecipientType.CC);

       if(address!=null)

          for(int i=0;i<address.length;i++) {

             out.print(address[i]+"  ");

          }

       else

          out.println("无");

    %>

    </td>

  </tr>

  <tr>

    <td>标题:</td>

    <td><%=message.getSubject()%></td>

  </tr>

  <tr>

    <td colspan=2>

    <br>   

    <%

       //body是一个用来标记是否点击了附件下载链接的参数,如果没有body参数,则只显示有几个附件以及它们的下载链接

       if(request.getParameter("body")==null)

       {

          //如果是一个多部分内容的e-mail

          if(message.isMimeType("multipart/*"))

          {

             //获得代表该e-mail的多部分内容的Multipart对象

             Multipart multipart = (Multipart)message.getContent();

             //依次获取Multipart对象的每个部分

             for(int i = 0;i < multipart.getCount();i++)

             {

               //得到每个部分的属性

               Part p = multipart.getBodyPart(i);

               String disposition = p.getDisposition();

               //如果该部分中是附件内容,则输出该附件的下载链接

               if ((disposition != null) &&(disposition.equals(Part.ATTACHMENT) || disposition.equals(Part.INLINE)))

               {

                  String filename=p.getFileName();

                  filename=javax.mail.internet.MimeUtility.decodeText(filename);

%>

<!--传递要看第几封e-mail的第几个附件-->

<p>

附件:

<a href="09_08.jsp?msg=<%=message.getMessageNumber()%>&host=<%=host%>&user=<%=user%>&password=<%=password%>&body=<%=i%>">

<%=filename%>

</a>

</p>

<%

               }

               else if(disposition==null)

               {

                  //如果该部分是普通文本内容(无附件),则输出其文本内容

                  if(p.isMimeType("text/plain")){

                      out.print(p.getContent());

                  }else {

                      //如果该部分是特殊附件,就不做处理

                  }

               }

             }

          }

          //如果是普通文本形式的e-mail,则显示其详细内容

          else if(message.isMimeType("text/plain"))

          {

              out.print(message.getContent());

          }

       }

     //如果有body参数,即表明用户点击了附件下载的链接,这时就可以下载相应的附件了

     else

     {

        //得到要下载的附件的编号

int attachNo=Integer.parseInt(request.getParameter("body"));

Part p;

//如果编号小于0,则表明是一个单部分的email

if(attachNo<0) p=message;

//否则是一个多部分组成的email,得到附件的对应部分

else{

Multipart multipart=(Multipart)message.getContent();

p=multipart.getBodyPart(attachNo);

}

//设置附件的类型属性

response.setContentType(p.getContentType());

//生成下载附件的头信息

String s=p.getFileName();

s=javax.mail.internet.MimeUtility.decodeText(s);

if (p.getFileName()!=null){

response.setHeader("Content-Disposition","attachment; filename=\""+s+"\"");

}

//设置下载过程中的输入流和输出流

OutputStream fout=response.getOutputStream();

InputStream fin=p.getInputStream();

//下载附件

int c=fin.read();

while(c!=-1)

{

   fout.write(c);

           c=fin.read();

}

     }

%>

    </td>

  </tr>

</table>

<%

   //关闭收件箱和到邮件服务器的连接

   inbox.close(true);

   store.close();

 }catch(MessagingException m)

 {

    out.println(m.toString());

 }

%>

<p><center>

<a href="09_06.jsp?host=<%=host%>&user=<%=user%>&password=<%=password%>">返回收件箱<a>

</center></p>

</body>

</html>

这个JSP程序在JSP程序7的基础之上填加了对附件的接收下载功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

等天晴i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值