像上一篇文章那样,我们只能创建一封封只包含纯文本或者HTML格式的文本邮件,这远远不能满足我们现在的需要,我们经常想要把本机上的图片、相片包含在邮件的正文部分,或者是直接将自己制作的贺卡等作为邮件正文发送给我们的朋友。

想要在邮件中包含图片、音频、视频等其他格式的文件,就不能再简单地使用 RFC 文档来对邮件结构、内容进行描述了,因为 RFC 只能描述普通的文本,而且一旦遇到单独一行的句号“.”时,SMTP 服务器就会以此为邮件正文部分的结束符,因此很大可能会导致邮件信息的丢失。

关于MIME:

引入 MIME (Multipurpose Internet Mail Extension ,多功能 Internet 邮件扩展)协议来满足我们上面的需求。使用了 MIME 协议描述的邮件可称为 MIME 邮件,一个 MIME 邮件可由若干个 符合 MIME 格式描述的消息组成。而一个消息既可以表示邮件中一个基本的 MIME 资源文件(例如纯文本、音频、视频等),又可以表示若干个此类基本资源文件组合而成的大的 MIME 消息的组合体。

一个 MIME 消息分为消息头和消息体,消息头包含对于消息体的描述,消息体则包含资源文件的具体内容。

JavaMail 中使用MIME:

在 JavaMail 中,一个 MIME 邮件用一个 MimeMessage 对象表示,仔细看下图:

其中标了红色圈圈的则是 MIME 消息的资源类型。

BodyPart 相当于上述的 MIME 基本消息;

MultiPart 相当于由多个 BodyPart (基本消息)组合而成的较大的 MIME 消息组合体;

Message 则相当于一封 MIME 邮件;

JavaMaill:使用MIME协议创建内含图片的复杂邮件_第1张图片  在上图中,我们看到 BodyPart 还可以再包含 MultiPart ,很明显这是一种组合结构、模式,或者说成树状结构。

注:下面的类都是抽象类,其实它们之下就有 MimeMessage 类、MimeMultiPart 类、MimeBodyPart 类一一对应,如下图:

JavaMaill:使用MIME协议创建内含图片的复杂邮件_第2张图片

 

好了,用代码来说明问题,实现一下,不管是否合适,我还是在代码中写上较多注释,其中有一些事必须注意的,代码如下:

   
   
   
   
  1. /**  
  2.  * 创建内含图片的邮件,保存为 Outlook 的 ".eml" 文件  
  3.  * @author haolloyin  
  4.  */ 
  5. public class WithPictureMessage {  
  6.     public static void main(String[] args) throws Exception{  
  7.  
  8.         String from = "[email protected]";  
  9.         String to = "[email protected]";  
  10.         String subject = "创建一个内含图片的邮件!";  
  11.         String body = "

    内含图片的邮件测试!!!

     "
     +  
  12.         " 蚂蚁

    "
     +   
  13.         "" +  
  14.         "cid:haolloyin_logo_jpg\">";  
  15.         /*  
  16.          *  上面的 cid 是指 MIME 协议中的 Content-ID 头,它是  
  17.          *  对于文件资源的唯一标识符,下面的 setContentID()方法  
  18.          *  中传入的 ID 号就必须与这个haolloyin_logo_jpg相一致  
  19.          */ 
  20.           
  21.         // 创建该邮件应用程序所需的环境信息以及会话信息  
  22.         Session session = Session.getDefaultInstance(new Properties());  
  23.           
  24.         // 以下几句是设置邮件的基本信息  
  25.         MimeMessage msg = new MimeMessage(session);       
  26.         msg.setFrom(new InternetAddress(from));       
  27.         msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));  
  28.         msg.setSubject(subject);  
  29.         msg.setSentDate(new Date());  
  30.           
  31.         /*  
  32.          *  创建一个子类型为 “related” 的 MIME 消息组合对象,  
  33.          *  其实 MimeMultipart 类还有另外两种子类型,请自行  
  34.          *  查阅并比较其中的适用场景  
  35.          */ 
  36.         MimeMultipart multipart = new MimeMultipart("related");  
  37.           
  38.         /*  
  39.          * 创建一个表示 HTML 正文部分的 MimeBodyPart 对象,   
  40.          * 并加入 到上一语句创建的 MimeMultiPart 对象中,  
  41.          * 由于 HTML 正文中包含中文,故下面应该指定字符集为 gbk 或 gb2312  
  42.          */ 
  43.         MimeBodyPart htmlBodyPart = new MimeBodyPart();  
  44.         htmlBodyPart.setContent(body, "text/html;charset=gbk");  
  45.         multipart.addBodyPart(htmlBodyPart);  
  46.           
  47.         /*  
  48.          *  创建一个表示图片文件的 MimeBodyPart 对象,  
  49.          *  并加入 到上面所创建的 MimeMultiPart 对象中,  
  50.          *  使用 JAF 框架中的 FileDataSource 类获取图片文件源,  
  51.          *  它能够自动获知文件的 MIME 格式并设置好消息头  
  52.          */ 
  53.         MimeBodyPart jpgBodyPart = new MimeBodyPart();  
  54.         FileDataSource fds = new FileDataSource("F:\\java\\haolloyin_logo.jpg");  
  55.         jpgBodyPart.setDataHandler(new DataHandler(fds));  
  56.         jpgBodyPart.setContentID("haolloyin_logo_jpg");  
  57.           
  58.         multipart.addBodyPart(jpgBodyPart);  
  59.           
  60.         /*  
  61.          *  这里不用再设置字符集了,因为上面的 HTML MimeBodyPart 对象中  
  62.          *  已经设置了,而图片文件的因为使用了 DataSource 对象,即 JAF 框架  
  63.          *  中的具体数据处理操作类,能够自动判断获知数据的 MIME 类型  
  64.          */ 
  65.         msg.setContent(multipart);  
  66.           
  67.         // 保存对邮件的修改并写入文件中  
  68.         msg.saveChanges();        
  69.         msg.writeTo(new FileOutputStream("withPictureMail.eml"));  
  70.     }  

编译、运行,生成 withPictureMail.eml 文件,双击打开,如下图:

JavaMaill:使用MIME协议创建内含图片的复杂邮件_第3张图片

 

JavaMaill:使用MIME协议创建内含图片的复杂邮件_第4张图片

在代码中的许多注释是比较重要的,必须要注意。此外,还可像上一篇文章中在 Outlook 中查看该 MIME 邮件的原始内容,其中应该既有 quoted-printable 编码也有 BASE64 编码方式,有兴趣的还可以看看各个消息头的格式是怎样的。

小结:

1、明白当 MIME 邮件需要附上多种格式(不仅仅是纯文本)的资源文件时,它是运用了层层嵌套的组合结构来表示、组织各个资源文件的;

2、在代码中的许多注释就是很重要的注意点了,必须掌握。

我的相关文章:

组合模式(Composite)的安全模式与透明模式

管道过滤器模式(Pipe and Filter)与组合模式(修改)

JavaMail入门:创建纯文本、HTML格式的邮件