JavaMail(JAVA邮件服务) API详解

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

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

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

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

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

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

4
MIME
MIME
并非用于传送邮件的协议,它做为多用途邮件的扩展定义了邮件内容的格式:信息格式、附件格式等等。一些RFC标准都涉及了MIMERFC 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协议。

3、安装
1
.安装JavaMail
为了使用JavaMail API,须要从http://java.sun.com/products/javamail/downloads/index.html下载文件名格式为javamail-[version].zip的文件(这个文件中包括了JavaMail实现),并将其中的mail.jar文件添加到CLASSPATH中。这个实现提供了对SMTPIMAP4POP3的支持。
注意:在安装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.jaractivation.jar都添加到了CLASSPATH中。
固然若是从方便的角度讲,直接把这两个Jar文件复制到JRE目录的lib/ext目录中也能够。

4、初次认识JavaMail API
1
.了解咱们的JavaMail环境
A
.纵览JavaMail核心类结构
打开JavaMail.jar文件,咱们将发如今javax.mail的包下面存在着一些核心类:SessionMessageAddressAuthenticatorTransportStoreFolder。并且在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
到这里,咱们已经创建了SessionMessage,下面将介绍如何使用邮件地址类:Address。像Message同样,Address类也是一个抽象类,因此咱们将使用javax.mail.internet.InternetAddress这个子类。
经过传入表明邮件地址的字符串,咱们能够创建一个邮件地址类:
Address address = new InternetAddress("president@whitehouse.gov"); 
若是要在邮件地址后面增长名字的话,能够经过传递两个参数:表明邮件地址和名字的字符串来创建一个具备邮件地址和名字的邮件地址类:
Address address = new InternetAddress("president@whitehouse.gov", "George Bush"); 
本文在这里所讲的邮件地址类是为了设置邮件信息的发信人和收信人而准备的,在创建了邮件地址类后,咱们经过messagesetFrom()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);
FTransport
在发送信息时,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
StoreFolder
接收邮件和发送邮件很相似都要用到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对象即目录对象将经过StoregetFolder()方法被返回,咱们可从这个Folder中读取邮件信息:
Folder folder = store.getFolder("INBOX");

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

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

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

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

5、使用JavaMail API
在明确了JavaMail API的核心部分如何工做后,本人将带领你们学习一些使用Java Mail API任务案例。
1
.发送邮件
在得到了Session后,创建并填入邮件信息,而后发送它到邮件服务器。这即是使用Java Mail API发送邮件的过程,在发送邮件以前,咱们须要设置SMTP服务器:经过设置Propertiesmail.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();
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]将抛出异常。

下面的代码片段有效的说明了如何读取邮件内容,在显示每一个邮件发信人和主题后,将出现用户提示从而获得用户是否读取该邮件的确认,若是输入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。这样就完成了邮件体与附件之间的关联工做,下面的工做就是BodyPartsetFileName()方法设置附件名为原文件名。

最后将两个邮件体放入到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.读取邮件中的附件
读取邮件中的附件的过程要比发送它的过程复杂一点。由于带有附件的邮件是多部分组成的,咱们必须处理每个部分得到邮件的内容和附件。
可是如何辨别邮件信息内容和附件呢?SunPart类(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头的引用。
处理内嵌图片就像向邮件中添加附件同样,不一样之处在于咱们必须经过设置图片附件所在的邮件体部分的headerContent-ID为一个随机字符串,并在HTMLimgsrc标记中设置为该字符串。这样就完成了图片附件与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抽象类来定义,在定义后咱们即可以使用FolderSearch()方法在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);
html

相关文章
相关标签/搜索