使用MIME协议创建内含图片的复杂邮件


像上一篇文章那样,我们只能创建一封封只包含纯文本或者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 邮件;

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

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

使用MIME协议创建内含图片的复杂邮件

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


  1. /**
  2. *创建内含图片的邮件,保存为Outlook的".eml"文件
  3. *@authorhaolloyin
  4. */
  5. publicclassWithPictureMessage{
  6. publicstaticvoidmain(String[]args)throwsException{
  7. Stringfrom="[email protected]";
  8. Stringto="[email protected]";
  9. Stringsubject="创建一个内含图片的邮件!";
  10. Stringbody="<h4>内含图片的邮件测试!!!</h4>"+
  11. "<ahref=http://haolloyin.blog.51cto.com/>蚂蚁</a></br></br>"+
  12. "<ahref=http://haolloyin.blog.51cto.com/>"+
  13. "<imgsrc=\"cid:haolloyin_logo_jpg\"></a>";
  14. /*
  15. *上面的cid是指MIME协议中的Content-ID头,它是
  16. *对于文件资源的唯一标识符,下面的setContentID()方法
  17. *中传入的ID号就必须与这个haolloyin_logo_jpg相一致
  18. */
  19. //创建该邮件应用程序所需的环境信息以及会话信息
  20. Sessionsession=Session.getDefaultInstance(newProperties());
  21. //以下几句是设置邮件的基本信息
  22. MimeMessagemsg=newMimeMessage(session);
  23. msg.setFrom(newInternetAddress(from));
  24. msg.setRecipients(Message.RecipientType.TO,InternetAddress.parse(to));
  25. msg.setSubject(subject);
  26. msg.setSentDate(newDate());
  27. /*
  28. *创建一个子类型为“related”的MIME消息组合对象,
  29. *其实MimeMultipart类还有另外两种子类型,请自行
  30. *查阅并比较其中的适用场景
  31. */
  32. MimeMultipartmultipart=newMimeMultipart("related");
  33. /*
  34. *创建一个表示HTML正文部分的MimeBodyPart对象,
  35. *并加入到上一语句创建的MimeMultiPart对象中,
  36. *由于HTML正文中包含中文,故下面应该指定字符集为gbk或gb2312
  37. */
  38. MimeBodyParthtmlBodyPart=newMimeBodyPart();
  39. htmlBodyPart.setContent(body,"text/html;charset=gbk");
  40. multipart.addBodyPart(htmlBodyPart);
  41. /*
  42. *创建一个表示图片文件的MimeBodyPart对象,
  43. *并加入到上面所创建的MimeMultiPart对象中,
  44. *使用JAF框架中的FileDataSource类获取图片文件源,
  45. *它能够自动获知文件的MIME格式并设置好消息头
  46. */
  47. MimeBodyPartjpgBodyPart=newMimeBodyPart();
  48. FileDataSourcefds=newFileDataSource("F:\\java\\haolloyin_logo.jpg");
  49. jpgBodyPart.setDataHandler(newDataHandler(fds));
  50. jpgBodyPart.setContentID("haolloyin_logo_jpg");
  51. multipart.addBodyPart(jpgBodyPart);
  52. /*
  53. *这里不用再设置字符集了,因为上面的HTMLMimeBodyPart对象中
  54. *已经设置了,而图片文件的因为使用了DataSource对象,即JAF框架
  55. *中的具体数据处理操作类,能够自动判断获知数据的MIME类型
  56. */
  57. msg.setContent(multipart);
  58. //保存对邮件的修改并写入文件中
  59. msg.saveChanges();
  60. msg.writeTo(newFileOutputStream("withPictureMail.eml"));
  61. }
  62. }

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

使用MIME协议创建内含图片的复杂邮件

使用MIME协议创建内含图片的复杂邮件

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

小结:

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

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