JavaMail-API详解

一、 JavaMail API 简介
JavaMail API
是读取、撰写、发送电子信息的可选包。我们可用它来建立如 Eudora Foxmail MS Outlook Express 一般的邮件用户代理程序( Mail User Agent, 简称 MUA )。而不是像 sendmail 或者其它的邮件传输代理( Mail Transfer Agent ,简称 MTA )程序那样可以传送、递送、转发邮件。从另外一个角度来看,我们这些电子邮件用户日常用 MUA 程序来读写邮件,而 MUA 依赖着 MTA 处理邮件的递送。
在清楚了到 MUA MTA 之间的关系后,让我们看看 JavaMail API 是如何提供信息访问功能的吧! JavaMail API 被设计用于以不依赖协议的方式去发送和接收电子信息,这个 API 被分为两大部分:

基本功能:如何以不依赖于协议的方式发送接收电子信息,这也是本文所要描述的,不过在下文中,大家将看到这只是一厢情愿而已。
第二个部分则是依赖特定协议的,比如 SMTP POP IMAP NNTP 协议。在这部分的 JavaMail API 是为了和服务器通讯,并不在本文的内容中。

二、相关协议一览
在我们步入 JavaMail API 之前,先看一下 API 所涉及的协议。以下便是大家日常所知、所乐于使用的 4 大信息传输协议:
SMTP
POP
IMAP
MIME
当然,上面的 4 个协议,并不是全部,还有 NNTP 和其它一些协议可用于传输信息,但是由于不常用到,所以本文便不提及了。理解这 4 个基本的协议有助于我们更好的使用 JavaMail API 。然而 JavaMail API 是被设计为与协议无关的,目前我们并不能克服这些协议的束缚。确切的说,如果我们使用的功能并不被我们选择的协议支持,那么 JavaMail API 并不可能如魔术师一样神奇的赋予我们这种能力。

1
SMTP
简单邮件传输协议定义了递送邮件的机制。在下文中,我们将使用基于 Java-Mail 的程序与公司或者 ISP SMTP 服务器进行通讯。这个 SMTP 服务器将邮件转发到接收者的 SMTP 服务器,直至最后被接收者通过 POP 或者 IMAP 协议获取。这并不需要 SMTP 服务器使用支持授权的邮件转发,但是却的确要注意 SMTP 服务器的正确设置( SMTP 服务器的设置与 JavaMail API 无关)。

2
POP
POP
是一种邮局协议,目前为第 3 个版本,即众所周知的 POP3 POP 定义了一种用户如何获得邮件的机制。它规定了每个用户使用一个单独的邮箱。大多数人在使用 POP 时所熟悉的功能并非都被支持,例如查看邮箱中的新邮件数量。而这个功能是微软的 Outlook 内建的,那么就说明微软 Outlook 之类的邮件客户端软件是通过查询最近收到的邮件来计算新邮件的数量来实现前面所说的功能。因此在我们使用 JavaMail API 时需要注意,当需要获得如前面所讲的新邮件数量之类的信息时,我们不得不自己进行计算。

3
IMAP
IMAP
使用在接收信息的高级协议,目前版本为第 4 版,所以也被称为 IMAP4 。需要注意的是在使用 IMAP 时,邮件服务器必须支持该协议。从这个方面讲,我们并不能完全使用 IMAP 来替代 POP ,不能期待 IMAP 在任何地方都被支持。假如邮件服务器支持 IMAP ,那么我们的邮件程序将能够具有以下被 IMAP 所支持的特性:每个用户在服务器上可具有多个目录,这些目录能在多个用户之间共享。
其与 POP 相比高级之处显而易见,但是在尝试采取 IMAP 时,我们认识到它并不是十分完美的:由于 IMAP 需要从其它服务器上接收新信息,将这些信息递送给用户,维护每个用户的多个目录,这都为邮件服务器带来了高负载。并且 IMAP POP 的一个不同之处是 POP 用户在接收邮件时将从邮件服务器上下载邮件,而 IMAP 允许用户直接访问邮件目录,所以在邮件服务器进行备份作业时,由于每个长期使用此邮件系统的用户所用的邮件目录会占有很大的空间,这将直接导致邮件服务器上磁盘空间暴涨。

4
MIME
MIME
并不是用于传送邮件的协议,它作为多用途邮件的扩展定义了邮件内容的格式:信息格式、附件格式等等。一些 RFC 标准都涉及了 MIME RFC 822, RFC 2045, RFC 2046, RFC 2047 ,有兴趣的 Matrixer 可以阅读一下。而作为 JavaMail API 的开发者,我们并不需关心这些格式定义,但是这些格式被用在了程序中。

5
NNTP 和其它的第三方协议
正因为 JavaMail API 在设计时考虑到与第三方协议实现提供商之间的分离,故我们可以很容易的添加一些第三方协议。 SUN 维护着一个第三方协议实现提供商的列表: http://java.sun.com/products/javamail/Third_Party.html ,通过此列表我们可以找到所需要的而又不被 SUN 提供支持的第三方协议:比如 NNTP 这个新闻组协议和 S/MIME 这个安全的 MIME 协议。

三、安装
1
.安装 JavaMail
为了使用 JavaMail API ,需要从 http://java.sun.com/products/javamail/downloads/index.html 下载文件名格式为 javamail-[version].zip 的文件(这个文件中包括了 JavaMail 实现),并将其中的 mail.jar 文件添加到 CLASSPATH 中。这个实现提供了对 SMTP IMAP4 POP3 的支持。
注意:在安装 JavaMail 实现之后,我们将在 demo 目录中发现许多有趣的简单实例程序。
在安装了 JavaMail 之后 , 我们还需要安装 JavaBeans Activation Framework ,因为这个框架是 JavaMail API 所需要的。如果我们使用 J2EE 的话,那么我们并无需单独下载 JavaMail ,因为它存在于 J2EE.jar 中,只需将 J2EE.jar 加入到 CLASSPATH 即可。

2
.安装 JavaBeans Activation Framework
http://java.sun.com/products/javabeans/glasgow/jaf.html 下载 JavaBeans Activation Framework ,并将其添加到 CLASSPATH 中。此框架增加了对任何数据块的分类、以及对它们的处理的特性。这些特性是 JavaMail API 需要的。虽然听起来这些特性非常模糊,但是它对于我们的 JavaMail API 来说只是提供了基本的 MIME 类型支持。
到此为止,我们应当把 mail.jar activation.jar 都添加到了 CLASSPATH 中。
当然如果从方便的角度讲,直接把这两个 Jar 文件复制到 JRE 目录的 lib/ext 目录中也可以。

四、初次认识 JavaMail API
1
.了解我们的 JavaMail 环境
A
.纵览 JavaMail 核心类结构
打开 JavaMail.jar 文件,我们将发现在 javax.mail 的包下面存在着一些核心类: Session Message Address Authenticator Transport Store Folder 。而且在 javax.mail.internet 包中还有一些常用的子类。
B
Session
Session
类定义了基本的邮件会话。就像 Http 会话那样,我们进行收发邮件的工作都是基于这个会话的。 Session 对象利用了 java.util.Properties 对象获得了邮件服务器、用户名、密码信息和整个应用程序都要使用到的共享信息。
Session
类的构造方法是私有的,所以我们可以使用 Session 类提供的 getDefaultInstance() 这个静态工厂方法获得一个默认的 Session 对象:
Properties props = new Properties();

// fill props with any information
Session session = Session.getDefaultInstance(props, null);
或者使用 getInstance() 这个静态工厂方法获得自定义的 Session: 
Properties props = new Properties();

// fill props with any information
Session session = Session.getInstance(props, null);
从上面的两个例子中不难发现, getDefaultInstance() getInstance() 方法的第二个参数都是 null ,这是因为在上面的例子中并没有使用到邮件授权,下文中将对授权进行详细介绍。
从很多的实例看,在对 mail server 进行访问的过程中使用共享的 Session 是足够的,即使是工作在多个用户邮箱的模式下也不例外。

C
Message
当我们建立了 Session 对象后,便可以被发送的构造信息体了。在这里 SUN 提供了 Message 类型来帮助开发者完成这项工作。由于 Message 是一个抽象类,大多数情况下,我们使用 javax.mail.internet.MimeMessage 这个子类,该类是使用 MIME 类型、 MIME 信息头的邮箱信息。信息头只能使用 US-ASCII 字符,而非 ASCII 字符将通过编码转换为 ASCII 的方式使用。
为了建立一个 MimeMessage 对象,我们必须将 Session 对象作为 MimeMessage 构造方法的参数传入:
MimeMessage message = new MimeMessage(session);
注意:对于 MimeMessage 类来讲存在着多种构造方法,比如使用输入流作为参数的构造方法。

在建立了 MimeMessage 对象后,我们需要设置它的各个 part ,对于 MimeMessage 类来说,这些 part 就是 MimePart 接口。最基本的设置信息内容的方法就是通过表示信息内容和米么类型的参数调用 setContent() 方法:
message.setContent("Hello", "text/plain");
然而,如果我们所使用的 MimeMessage 中信息内容是文本的话,我们便可以直接使用 setText() 方法来方便的设置文本内容。
message.setText("Hello");
前面所讲的两种方法,对于文本信息,后者更为合适。而对于其它的一些信息类型,比如 HTML 信息,则要使用前者。
别忘记了,使用 setSubject() 方法对邮件设置邮件主题:
message.setSubject("First");

D
Address
到这里,我们已经建立了 Session Message ,下面将介绍如何使用邮件地址类: Address 。像 Message 一样, Address 类也是一个抽象类,所以我们将使用 javax.mail.internet.InternetAddress 这个子类。
通过传入代表邮件地址的字符串,我们可以建立一个邮件地址类:
Address address = new InternetAddress("president@whitehouse.gov"); 
如果要在邮件地址后面增加名字的话,可以通过传递两个参数:代表邮件地址和名字的字符串来建立一个具有邮件地址和名字的邮件地址类:
Address address = new InternetAddress("president@whitehouse.gov", "George Bush"); 
本文在这里所讲的邮件地址类是为了设置邮件信息的发信人和收信人而准备的,在建立了邮件地址类后,我们通过 message setFrom() setReplyTo() 两种方法设置邮件的发信人:
message.setFrom(address);

message.setReplyTo(address);
若在邮件中存在多个发信人地址,我们可用 addForm() 方法增加发信人:
Address address[ ] = ...;message.addFrom(address);
为了设置收信人,我们使用 addRecipient() 方法增加收信人,此方法需要使用 Message.RecipientType 的常量来区分收信人的类型:
message.addRecipient(type, address)
下面是 Message.RecipientType 的三个常量 :
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
并没有提供检查邮件地址有效性的机制。当然我们可以自己完成这个功能:验证邮件地址的字符是否按照 RFC822 规定的格式书写或者通过 DNS 服务器上的 MX 记录验证等。

E
Authenticator
java.net 类那样, JavaMail API 通过使用授权者类( Authenticator )以用户名、密码的方式访问那些受到保护的资源,在这里 资源 就是指邮件服务器。在 javax.mail 包中可以找到这个 JavaMail 的授权者类( Authenticator )。
在使用 Authenticator 这个抽象类时,我们必须采用继承该抽象类的方式,并且该继承类必须具有返回 PasswordAuthentication 对象(用于存储认证时要用到的用户名、密码) getPasswordAuthentication() 方法。并且要在 Session 中进行注册,使 Session 能够了解在认证时该使用哪个类。
下面代码片断中的 MyAuthenticator 就是一个 Authenticator 的子类。
Properties props = new Properties();

// fill props with any information
Authenticator auth = new MyAuthenticator();
Session session = Session.getDefaultInstance(props, auth);
F Transport
在发送信息时, Transport 类将被用到。这个类实现了发送信息的协议(通称为 SMTP ),此类是一个抽象类,我们可以使用这个类的静态方法 send() 来发送消息:
Transport.send(message);
当然,方法是多样的。我们也可由 Session 获得相应协议对应的 Transport 实例。并通过传递用户名、密码、邮件服务器主机名等参数建立与邮件服务器的连接,并使用 sendMessage() 方法将信息发送,最后关闭连接:
message.saveChanges();

// implicit with send()
Transport transport = session.getTransport("smtp");
transport.connect(host, username, password);
transport.sendMessage(message, message.getAllRecipients());
transport.close();
评论:上面的方法是一个很好的方法,尤其是在我们在同一个邮件服务器上发送多个邮件时。因为这时我们将在连接邮件服务器后连续发送邮件,然后再关闭掉连接。 send() 这个基本的方法是在每次调用时进行与邮件服务器的连接的,对于在同一个邮件服务器上发送多个邮件来讲可谓低效的方式。
注意:如果需要在发送邮件过程中监控 mail 命令的话,可以在发送前设置 debug 标志:
session.setDebug(true)


G
Store Folder
接收邮件和发送邮件很类似都要用到 Session 。但是在获得 Session 后,我们需要从 Session 中获取特定类型的 Store ,然后连接到 Store ,这里的 Store 代表了存储邮件的邮件服务器。在连接 Store 的过程中,极有可能需要用到用户名、密码或者 Authenticator
// Store store = session.getStore("imap");

Store store = session.getStore("pop3");
store.connect(host, username, password);
在连接到 Store 后,一个 Folder 对象即目录对象将通过 Store getFolder() 方法被返回,我们可从这个 Folder 中读取邮件信息:
Folder folder = store.getFolder("INBOX");

folder.open(Folder.READ_ONLY);
Message message[] = folder.getMessages();
上面的例子首先从 Store 中获得 INBOX 这个 Folder (对于 POP3 协议只有一个名为 INBOX Folder 有效),然后以只读( Folder.READ_ONLY )的方式打开 Folder ,最后调用 Folder getMessages() 方法得到目录中所有 Message 的数组。

注意:对于 POP3 协议只有一个名为 INBOX Folder 有效,而对于 IMAP 协议,我们可以访问多个 Folder (想想前面讲的 IMAP 协议)。而且 SUN 在设计 Folder getMessages() 方法时采取了很智能的方式:首先接收新邮件列表,然后再需要的时候(比如读取邮件内容)才从邮件服务器读取邮件内容。
在读取邮件时,我们可以用 Message 类的 getContent() 方法接收邮件或是 writeTo() 方法将邮件保存, getContent() 方法只接收邮件内容(不包含邮件头),而 writeTo() 方法将包括邮件头。
System.out.println(((MimeMessage)message).getContent());
在读取邮件内容后,别忘记了关闭 Folder Store
folder.close(aBoolean);

store.close();
传递给 Folder.close() 方法的 boolean  类型参数表示是否在删除操作邮件后更新 Folder  

H
.继续向前进!
在讲解了以上的七个 Java Mail 核心类定义和理解了简单的代码片断后,下文将详细讲解怎样使用这些类实现 JavaMail API 所要完成的高级功能。

五、使用 JavaMail API
在明确了 JavaMail API 的核心部分如何工作后,本人将带领大家学习一些使用 Java Mail API 任务案例。
1
.发送邮件
在获得了 Session 后,建立并填入邮件信息,然后发送它到邮件服务器。这便是使用 Java Mail API 发送邮件的过程,在发送邮件之前,我们需要设置 SMTP 服务器:通过设置 Properties mail.smtp.host 属性。
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 结构块中。

2
.接收邮件
为了在读取邮件,我们获得了 session ,并且连接到了邮箱的相应 store ,打开相应的 Folder ,然后得到我们想要的邮件,当然别忘记了在结束时关闭连接。
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();
f or (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] 将抛出异常。

下面的代码片断有效的说明了如何读取邮件内容,在显示每个邮件发信人和主题后,将出现用户提示从而得到用户是否读取该邮件的确认,如果输入 YES 的话,我们可用 Message.writeTo(java.io.OutputStream os) 方法将邮件内容输出到控制台上,关于 Message.writeTo() 的具体用法请看 JavaMail API
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;  }}
3
.删除邮件和标志
设置与 message 相关的 Flags 是删除邮件的常用方法。这些 Flags 表示了一些系统定义和用户定义的不同状态。在 Flags 类的内部类 Flag 中预定义了一些标志:
Flags.Flag.ANSWERED
Flags.Flag.DELETED
Flags.Flag.DRAFT
Flags.Flag.FLAGGED
Flags.Flag.RECENT
Flags.Flag.SEEN
Flags.Flag.USER
但需要在使用时注意的:标志存在并非意味着这个标志被所有的邮件服务器所支持。例如,对于删除邮件的操作, POP 协议不支持上面的任何一个。所以要确定哪些标志是被支持的 ?? 通过访问一个已经打开的 Folder 对象的 getPermanetFlags() 方法,它将返回当前被支持的 Flags 类对象。
删除邮件时,我们可以设置邮件的 DELETED 标志:  
message.setFlag(Flags.Flag.DELETED, true);
但是首先要采用 READ_WRITE 的方式打开 Folder
folder.open(Folder.READ_WRITE);
在对邮件进行删除操作后关闭 Folder 时,需要传递一个 true 作为对删除邮件的擦除确认。
folder.close(true);
Folder
类中另一种用于删除邮件的方法 expunge() 也同样可删除邮件,但是它并不为 sun 提供的 POP3 实现支持,而其它第三方提供的 POP3 实现支持或者并不支持这种方法。
另外,介绍一种检查某个标志是否被设置的方法: Message.isSet(Flags.Flag flag) 方法,其中参数为被检查的标志。

4
.邮件认证
我们在前面已经学会了如何使用 Authenticator 类来代替直接使用用户名和密码这两字符串作为 Session.getDefaultInstance() 或者 Session.getInstance() 方法的参数。在前面的小试牛刀后,现在我们将了解到全面认识一下邮件认证。
我们在此取代了直接使用邮件服务器主机名、用户名、密码这三个字符串作为连接到 POP3 Store 的方式,使用存储了邮件服务器主机名信息的属性文件,并在获得 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();

PopupAuthenticator
类继承了抽象类 Authenticator ,并且通过重载 Authenticator 类的 getPasswordAuthentication() 方法返回 PasswordAuthentication 类对象。而 getPasswordAuthentication() 方法的参数 param 是以逗号分割的用户名、密码组成的字符串。
import javax.mail.*;

import java.util.*;
public class PopupAuthenticator extends Authenticator {  
public PasswordAuthentication getPasswordAuthentication(String param) {
String username, password;    
StringTokenizer st = new StringTokenizer(param, ","); 
username = st.nextToken();
password = st.nextToken(); 
return new PasswordAuthentication(username, password);  
}
}
5 .回复邮件
回复邮件的方法很简单:使用 Message 类的 reply() 方法,通过配置回复邮件的收件人地址和主题(如果没有提供主题的话,系统将默认将 “Re 作为邮件的主体),这里不需要设置任何的邮件内容,只要复制发信人或者 reply-to 到新的收件人。而 reply() 方法中的 boolean 参数表示是否将邮件回复给发送者(参数值为 false ),或是恢复给所有人(参数值为 true )。
补充一下, reply-to 地址需要在发信时使用 setReplyTo() 方法设置。
MimeMessage reply = (MimeMessage)message.reply(false); reply.setFrom(new InternetAddress("president@whitehouse.gov")); reply.setText("Thanks");Transport.send(reply);
6
.转发邮件
转发邮件的过程不如前面的回复邮件那样简单,它将建立一个转发邮件,这并非一个方法就能做到。
每个邮件是由多个部分组成,每个部分称为一个邮件体部分,是一个 BodyPart 类对象,对于 MIME 类型邮件来讲就是 MimeBodyPart 类对象。这些邮件体包含在成为 Multipart 的容器中对于 MIME 类型邮件来讲就是 MimeMultiPart 类对象。在转发邮件时,我们建立一个文字邮件体部分和一个被转发的文字邮件体部分,然后将这两个邮件体放到一个 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 contentmessage
BodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler(message.getDataHandler());
// Add part to multi part
multipart.addBodyPart(messageBodyPart);
// Associate multi-part with messageforward.
setContent(multipart);
// Send message
Transport.send(forward);

7
.使用附件
附件作为与邮件相关的资源经常以文本、表格、图片等格式出现,如流行的邮件客户端一样,我们可以用 JavaMail API 从邮件中获取附件或是发送带有附件的邮件。

A
.发送带有附件的邮件
发送带有附件的邮件的过程有些类似转发邮件,我们需要建立一个完整邮件的各个邮件体部分,在第一个部分(即我们的邮件内容文字)后,增加一个具有 DataHandler 的附件而不是在转发邮件时那样复制第一个部分的 DataHandler

如果我们将文件作为附件发送,那么要建立 FileDataSource 类型的对象作为附件数据源;如果从 URL 读取数据作为附件发送,那么将要建立 URLDataSource 类型的对象作为附件数据源。

然后将这个数据源( FileDataSource 或是 URLDataSource )对象作为 DataHandler 类构造方法的参数传入,从而建立一个 DataHandler 对象作为数据源的 DataHandler

接着将这个 DataHandler 设置为邮件体部分的 DataHandler 。这样就完成了邮件体与附件之间的关联工作,下面的工作就是 BodyPart setFileName() 方法设置附件名为原文件名。

最后将两个邮件体放入到 Multipart 中,设置邮件内容为这个容器 Multipart ,发送邮件。
// 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 messagemessage
BodyPart.setText("Pardon Ideas");
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
// Part two is attachmentmessageBodyPart = 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 实现发送带有附件的邮件,则必须上传附件给 servlet ,这时需要注意提交页面 form 中对编码类型的设置应为 multipart/form-data
<form enctype="multipartform-data"     method=''post action="/myservlet"''>
<input type="file"bane="thefile">
<input type= "submit" value="upload">

B .读取邮件中的附件
读取邮件中的附件的过程要比发送它的过程复杂一点。因为带有附件的邮件是多部分组成的,我们必须处理每一个部分获得邮件的内容和附件。
但是如何辨别邮件信息内容和附件呢? Sun Part 类( BodyPart 类实现的接口类)中提供了 getDisposition() 方法让开发者获得邮件体部分的部署类型,当该部分是附件时,其返回之将是 Part.ATTACHMENT 。但附件也可以没有部署类型的方式存在或者部署类型为 Part.INLINE ,无论部署类型为 Part.ATTACHMENT 还是 Part.INLINE ,我们都能把该邮件体部分导出保存。
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);
}
以上是邮件体部分被正确设置的简单例子,如果邮件体部分的部署类型为 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, ...  }
...}

8 .处理 HTML 邮件
前面的例子中发送的邮件都是以文本为内容的(除了附件),下面将介绍如何接收和发送基于 HTML 的邮件。
A .发送 HTML 邮件
假如我们需要发送一个 HTML 文件作为邮件内容,并使邮件客户端在读取邮件时获取相关的图片或者文字的话,只要设置邮件内容为 html 代码,并设置内容类型为 text/html 即可:
String htmlText = " Hello " +message.setContent(htmlText, "text/html"));
请注意:这里的图片并不是在邮件中内嵌的,而是在 URL 中定义的。邮件接收者只有在线时才能看到。
在接收邮件时,如果我们使用 JavaMail API 接收邮件的话是无法实现以 HTML 方式显示邮件内容的。因为 JavaMail API 邮件内容视为二进制流。所以要显示 HTML 内容的邮件,我们必须使用 JEditorPane 或者第三方 HTML 展现组件。

以下代码显示了如何使用 JEditorPane 显示邮件内容:
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();}

B .在邮件中包含图片
如果我们在邮件中使用 HTML 作为内容,那么最好将 HTML 中使用的图片作为邮件的一部分,这样无论是否在线都会正确的显示 HTML 中的图片。处理方法就是将 HTML 中用到的图片作为邮件附件并使用特殊的 cid URL 作为图片的引用,这个 cid 就是对图片附件的 Content-ID 头的引用。
处理内嵌图片就像向邮件中添加附件一样,不同之处在于我们必须通过设置图片附件所在的邮件体部分的 header Content-ID 为一个随机字符串,并在 HTML img src 标记中设置为该字符串。这样就完成了图片附件与 HTML 的关联。
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 = " Hello" + "<CCID_FILE VALUES="\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 imagemessageBodyPart = new MimeBodyPart();
// Fetch the image and associate to par
tDataSource fds = new FileDataSource(file);
messageBodyPart.setDataHandler(new DataHandler(fds));
messageBodyPart.setHeader("Content-ID","");
// Add part to multi-part
multipart.addBodyPart(messageBodyPart);
// Associate multi-part with message
message.setContent(multipart);
9 .在邮件中搜索短语
JavaMail API
提供了过滤器机制,它被用来建立搜索短语。这个短语由 javax.mail.search 包中的 SearchTerm 抽象类来定义,在定义后我们便可以使用 Folder Search() 方法在 Folder 中查找邮件:
SearchTerm st = ...;Message[] msgs = folder.search(st);
下面有 22 个不同的类(继承了 SearchTerm 类)供我们使用:
AND terms (class AndTerm)
OR terms (class OrTerm)
NOT terms (class NotTerm)
SENT DATE terms (class SentDateTerm)
CONTENT terms (class BodyTerm)
HEADER terms (FromTerm / FromStringTerm, RecipientTerm / RecipientStringTerm, SubjectTerm, etc.)
使用这些类定义的断语集合,我们可以构造一个逻辑表达式,并在 Folder 中进行搜索。下面是一个实例:在 Folder 中搜索邮件主题含有 “ADV” 字符串或者发信人地址为 friend@public.com 的邮件。
SearchTerm st =   new OrTerm(    new SubjectTerm("ADV:"), 

new FromStringTerm("friend@public.com"));
Message[] msgs = folder.search(st);

六、参考资源
JavaMail API Home
Sun’s JavaMail API
基础
JavaBeans Activation Framework Home
javamail-interest mailing list
Sun''s JavaMail FAQ
jGuru''s JavaMail FAQ
Third Party Products List
七、代码下载
http://java.sun.com/developer/onlineTraining/JavaMail/exercises.html
  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值