JavaMail原理解析

JavaMail API中定义了一个javax.mail.Store类,它用于执行邮件接收任务,这个类的实例对象封装了某种邮件接收协议的底层实施细节,应用程序调用这个类中的方法就可以获得用户邮箱中的各个邮件夹的信息。JavaMail使用Folder对象表示邮件夹,通过Folder对象的方法应用程序进而又可以获得该邮件夹中的所有邮件信息,而每封邮件信息,JavaMail又分别使用了一个Message对象进行封装。

Store类:与Transport类一样,javax.mail.Store类也继承了Java.mail.Service类。Store类用于连接邮件接收服务器,并访问邮件接收服务器上的邮箱夹。Store类是一个抽象类,Sun公司在mail.jar包的com/sun/mail/pop3目录中提供了POP3协议的实现子类POP3Store,POP3Store封装了POP3协议的底层实施细节。应用程序通常调用Session.getStore方法得到Store类的实例对象,这个方法根据Session对象中定义的mail.store.procotol属性构建相应的协议实现类,并返回该类的实例对象。

1.接收邮件的具体过程如下:

(1).从Session对象中获得实现了某种邮件发送协议的Store对象。

  1. Properties props = new Properties();  
  2. //存储接收邮件服务器使用的协议,这里以POP3为例  
  3. props.setProperty("mail.store.protocol", “pop3”);  
  4. //设置接收邮件服务器的地址,这里还是以网易163为例  
  5. props.setProperty("mail.pop3.host", "pop3.163.com");  
  6. //根据属性新建一个邮件会话.  
  7. Session session=Session.getInstance(props);  
  8. //从会话对象中获得POP3协议的Store对象  
  9. Store store = session.getStore("pop3");  
  10. //如果需要查看接收邮件的详细信息,需要设置Debug标志  
  11. session.setDebug(false);  
 

(2).以某个邮箱帐户的身份连接上POP3 或IMAP4服务器。

  1. //连接邮件服务器  
  2. store.connect("pop3.163.com", username, password);  
 

(3).调用Store的getFolder方法,获取代表该帐户的邮箱中的某个邮件夹的Folder对象。

  1. //获取邮件服务器的收件箱  
  2. Folder folder = store.getFolder("INBOX");  
  3. //以只读权限打开收件箱  
  4. folder.open(Folder.READ_ONLY);  
 

注意:JavaMail在Folder类中定义了两个用于表示操作权限的常量:

a. Folder.READ_ONLY:表示只读权限。

b. Folder.READ_WRITE:表示可以修改并读取邮件夹中的邮件。

(4).调用Folder对象中的getMessage或getMessages方法,获取邮件夹中的一封邮件或所有邮件,每封邮件以一个Message对象返回。

  1. //获取收件箱中的邮件,也可以使用getMessage(int 邮件的编号)来获取具体某一封邮件  
  2. Message message[] = folder.getMessages();  
  3. for (int i=0, n=message.length; i<n; i++) {    
  4.        获取邮件具体信息  
  5. }  
  6. //关闭连接  
  7. folder.close(false);  
  8. store.close();  
 

(5).读取邮件内容:

a.用Message.writeTo(java.io.OutputStream os)方法将邮件内容读入输出流中。

b.也可以使用getContent();获取邮件内容,返回一个Object对象。

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

  1. Multipart mp = (Multipart)message.getContent();  
  2. for (int i=0, n=multipart.getCount(); i<n; i++) {  
  3. Part part = multipart.getBodyPart(i));   
  4. String disposition = part.getDisposition();   
  5. if ((disposition != null) &&        
  6. ((disposition.equals(Part.ATTACHMENT) ||         
  7. (disposition.equals(Part.INLINE))) {     
  8. saveFile(part.getFileName(), part.getInputStream());  
  9.  }  
  10. }  
 

上述代码中使用了saveFile方法是自定义的方法,它根据附件的文件名建立一个文件,如果本地磁盘上存在名为附件的文件,那么将在文件名后增加数字表示区别。然后从邮件体中读取数据写入到本地文件中。

3.标记邮件:

标记邮件就是把邮件标记为已读,删除等操作,需要使用Flags类,它mail.jar包中的Flags类代表以组邮件标记的集合,邮件标记用于标示邮件的使用情况,例如邮件的删除标记、已读标记等。JavaMail中的邮件标记分为系统标记和用户标记,系统标记指Flags.Flag这个内部类中表示的邮件标记,用户标记指用户自定义的标记。

Flags.Flag类:是Flags的内部类,以定义了一些常量类分别表示各种不同的邮件标记,这些邮件标记都是系统标记。如下所示:

      

Flags.Flag.ANSWERED

邮件回复标记,标识邮件是否已回复。

Flags.Flag.DELETED

邮件删除标记,标识邮件是否需要删除。

Flags.Flag.DRAFT

草稿邮件标记,标识邮件是否为草稿。

Flags.Flag.FLAGGED

表示邮件是否为回收站中的邮件。

Flags.Flag.RECENT

新邮件标记,表示邮件是否为新邮件。

Flags.Flag.SEEN

邮件阅读标记,标识邮件是否已被阅读。

Flags.Flag.USER

底层系统是否支持用户自定义标记,应用程序只能检索这个属性,而不能设置这个属性。

标记邮件的操作如下:

(1).设置邮件标记:

  1. //设置标记时需要以读写权限打开收件箱  
  2. Folder.open(Folder.READ_WRITE);  
  3. //设置标记  
  4. Message.setFlag(标记,true);  
  5. Message.saveChanges();  
 

(2).清除邮件标记

  1. //清除邮件标记时也需要以读写权限打开收件箱  
  2. Folder.open(Folder.READ_WRITE);  
  3. //获取邮件标记  
  4. Flags flags=message.getFlags();  
  5. If(flags.contains(Flags.Flag))  
  6. {     //清除邮件标记  
  7.        Message.setFlag(Flags.Flag,false);  
  8. }  
  9. Message.saveChanges();  
 

4.搜索邮件:

JavaMail在javax.mail.search包中定义了一个用于创建搜索条件的SearchTerm类,应用程序创建SearchTerm类的实例对象以后,就可以调用Folder.search(SearchTerm st)方法搜索邮件夹中符合搜索条件的所有邮件。SearchTerm类是一个抽象类,JavaMail提供了22个实现子类以帮助应用程序创建不同的搜索条件。如下:

(1).用于创建逻辑组合关系的类

AND条件(AndTerm类)

OR条件(OrTerm类)

NOT条件(NotTerm类)

Comparison条件(ComparisonTerm类)

(2).用于创建具体搜索条件的类

DATE条件(SendDateTerm、ReceinedDateTerm类)

CONTENT条件(BodyTerm类)

HEADER条件(FormStringTerm,RecipientStringTerm,SubjectTerm类等)

具体用法如下:

a.      搜索邮件夹中所有从[email protected][email protected]法来的邮件。

  1. //创建搜索条件  
  2. SearchTerm st=new OrTerm (new FromStringTerm(“[email protected]”),  
  3. new FromStringTerm(“[email protected]”));  
  4. //搜索邮件  
  5. Message[] msgs=folder.search(st);  
 

b.      搜索所有今天收到的,并且是[email protected]这个地址发来的邮件。

  1. //创建搜索条件  
  2. SearchTerm st=new AndTerm(new FromStringTerm(“[email protected]”),  
  3. new ReceivedDateTerm(ComparisonTerm.EQ,new Date()));  
  4. //搜索邮件  
  5. Message [] msgs=folder.search(st);  
 

5.解析和显示邮件

解析和显示一封邮件就是把封装在Message对象中的数据解析出来,包括邮件头中的邮件发送者地址、邮件主体、发送时间,邮件正文中的文本信息、内嵌资源,邮件体中的附件信息等,然后把解析出来的这些信息交给数据显示软件显示。

JavaMail解析邮件的流程如下:

(1).调用Message对象的getForm,getSubject等方法,可以得到邮件发送人和主题等信息,调用getContentType方法得到邮件的类型。

(2).通过Message.getContentType方法的返回值判断邮件类型,并调用Message.getContent方法得到邮件内容。如果邮件类型为“text/plain”或”text/html”,表示邮件为纯文本,此时调用Message对象的getContent方法得到邮件内容,然后将返回对象的类型转换成String输出给显示软件即可。如果邮件类型为”multipart/*”,表示邮件内容是一个复合类型,此时需将Message.getContent方法返回的对象转换成Multipart。

(3). 调用Multipart对象的getCount方法检测Multipart对象中封装了多少个BodyPart对象,并通过for循环逐一取出Multipart对象中的每个BodyPart对象进行处理。

(4). 在处理每个BodyPart对象时,首先调用BodyPart对象的getContentType方法得到他的MIME类型,然后根据MIME类型做出如下三种情况的处理:

a.当MIME类型表示的是图片、声音或附件等二进制数据时,此时应调用BodyPart对象的getDataHandler方法得到封装了数据的DataHandler对象,然后调用DataHandler对象的getInputStream方法获得与数据相关的InputStream对象,通过这个InputStream对象中即可获得原始的二进制数据内容。

b.当MIME类型为”text/*”时,表示BodyPart对象中保存的是纯文本数据,此时调用BodyPart对象的getContent方法并将返回的对象转换成String输出给显示软键显示即可。

c.当MIME类型是”multipart/mixed”时,表示BodyPart对象中保存的是一个复合MIME消息,此时调用BodyPart对象中的getContent方法得到封装复合MIME消息的对象并将它转换成Multipart类型。

猜你喜欢

转载自blog.csdn.net/weixin_37962025/article/details/76145276