邮件原理与JavaMail开发(二)——使用JavaMail创建邮件和发送邮件

时间:2021-09-14 18:11:16

在上一篇文章中我们就已经讲解过RFC822文档规范了,但讲解的不够仔细,所以我们该全面而细致地叙述该文档规范了,那这篇文章就以它作为开头展开吧!

RFC882文档简单说明

RFC882文档规定了如何编写一封简单的邮件(纯文本邮件),一封简单的邮件包含邮件头和邮件体两个部分,邮件头和邮件体之间使用空行分隔。
邮件头包含的内容有:

  • from字段:用于指明发件人
  • to字段:用于指明收件人
  • subject字段:用于说明邮件主题
  • cc字段:抄送,将邮件发送给收件人的同时抄送给另一个收件人,收件人可以看到邮件抄送给了谁。
  • bcc字段:密送,将邮件发送给收件人的同时将邮件秘密发送给另一个收件人,收件人无法看到邮件密送给了谁。

邮件体指的就是邮件的具体内容。
提示:可利用RFC822文档漏洞发送假冒邮件
在上一篇文章中,我们是使用telnet客户端连接上163的邮件服务器然后发一封Email到sina的邮箱中去,现在我们来编写java程序来做这件事情,但这需要我们熟悉socket编程,但我已经忘记了,哈哈哈!!!

public class Demo {

public static void main(String[] args) throws Exception {
// yerenyuan10001@163.com向i_beautifulman@sina.com发送一封Email
Socket socket = new Socket("smtp.163.com", 25);
// 通过br读取服务器回送的数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 通过out向服务器写数据
OutputStream out = socket.getOutputStream();

System.out.println(br.readLine());
out.write("ehlo hello\r\n".getBytes());

System.out.println(br.readLine());
System.out.println(br.readLine());
System.out.println(br.readLine());
System.out.println(br.readLine());
System.out.println(br.readLine());
System.out.println(br.readLine());
System.out.println(br.readLine());

out.write("auth login\r\n".getBytes());
System.out.println(br.readLine());

out.write("eWVyZW55DEWREdWFuMTAwMDE=\r\n".getBytes()); // 用户名必须是经过base64编码处理
System.out.println(br.readLine());

out.write("MTAwMDF5DEREWTRZXJlbnl1YW4=\r\n".getBytes()); // 密码也必须是经过base64编码处理
System.out.println(br.readLine());

out.write("mail from: <yerenyuan10001@163.com>\r\n".getBytes());
System.out.println(br.readLine());

out.write("rcpt to: <i_beautifulman@sina.com>\r\n".getBytes());
System.out.println(br.readLine());

out.write("data\r\n".getBytes());
System.out.println(br.readLine());

out.write("from: <yerenyuan10001@163.com>\r\nto: <i_beautifulman@sina.com>\r\nsubject: my love\r\n\r\nhello my lover\r\n".getBytes());
out.write(".\r\n".getBytes());
System.out.println(br.readLine());

out.write("quit\r\n".getBytes());
System.out.println(br.readLine());

br.close();
out.close();
socket.close();
}

}

运行该程序,然后登陆到i_beautifulman@sina.com邮箱当中,就可以收取到由yerenyuan10001@163.com发送的Email了,如下图所示:
邮件原理与JavaMail开发(二)——使用JavaMail创建邮件和发送邮件

MIME协议简单介绍

在我们的实际开发当中,一封邮件既可能包含图片,又可能包含有附件,在这样的情况下,RFC882文档规定的邮件格式就无法满足要求了,毕竟RFC882文档是70年代的产物,已不符合如今的开发需求了,这时就应运而生了MIME协议。
MIME协议是对RFC822文档的升级和补充,它描述了如何生产一封复杂的邮件。通常我们把MIME协议描述的邮件称之为MIME邮件MIME协议描述的数据称之为MIME消息
对于一封复杂邮件,如果包含了多个不同的数据,MIME协议规定了要使用分隔线对多段数据进行分隔,并使用Content-Type头字段对数据的类型、以及多个数据之间的关系进行描述。

MIME协议常用头字段

Content-type头字段

  • 描述数据的类型
    以“主类型/子类型”的形式出现,主类型有text、image、audio、video、application、message等,分别表示文本、图片、音频、视频、应用程序、组合结构、消息等。每个主类型下面都有多个子类型,例如text主类型包含plain、html、xml、css等子类型。
  • 描述多个数据之间的关系
    • multipart/related:描述(多个)数据之间的关系是关联关系。
    • multipart/mixed:描述(多个)数据之间没有关系,但没有关系也是一种关系。
    • multipart/alternative:描述(多个)数据之间的关系是二选其一的关系,这种关系用到的是最少的。

Content-Disposition头字段

Content-Disposition头字段用于指定邮件阅读程序处理数据内容的方式,有inline和attachment两种标准方式,inline表示直接处理,而attachment表示当作附件处理。如果将Content-Disposition设置为attachment,在其后还可以指定filename属性,如下所示:

Content-Disposition: attachment; filename=“1.bmp”

上面的MIME头字段表示MIME消息体的内容为邮件附件,附件名“1.bmp”。

Content-ID头字段

Content-ID头字段用于为“multipart/related”组合消息中的内嵌资源指定一个唯一标识号,在HTML格式的正文中可以使用这个唯一标识号来引用该内嵌资源。例如,假设将一个表示内嵌图片的MIME消息的Content-ID头字段设置为如下形式:

Content-ID: it315logo_gif

那么,在HTML正文中就需要使用如下HTML语句来引用该图片资源:

<img src="cid:it315logo_gif">

注意,在引用Content-ID头字段标识的内嵌资源时,要在资源的唯一标识号前面加上“cid:“,以说明要采用唯一标识号对资源进行引用。

使用JavaMail API创建邮件

JavaMail创建的邮件是基于MIME协议的。因此可以使用JavaMail创建出包含图片,包含附件的复杂邮件。

邮件组织结构相关的API

  • MimeMessage类表示整封邮件。
  • MimeBodyPart类表示邮件的一个MIME消息。(即保存邮件某一部分数据的容器)
  • MimeMultipart类表示一个由多个MIME消息组合成的组合MIME消息。(即保存MimeBodyPart的容器)

用图来表示会更加清晰:
邮件原理与JavaMail开发(二)——使用JavaMail创建邮件和发送邮件

接下来到了创建邮件的时刻了,我们首先编写一个创建邮件测试项目,准备测试环境,如下:
邮件原理与JavaMail开发(二)——使用JavaMail创建邮件和发送邮件

  • javax.mail.jar:使用JavaMail API创建邮件和发送邮件所需的jar包。
    JavaMail API,顾名思义,提供给开发者处理电子邮件相关的编程接口。它是SUN发布的用来处理email的API,它可以方便地执行一些常用的邮件传输。我们可以基于JavaMail开发出类似于Microsoft Outlook的应用程序。
    人们常说J2EE技术有13种,JavaMail就是其中一种。
  • activation.jar:与jaf技术相关jar包。
    jaf也是J2EE 13种技术中的一种。

创建简单邮件

使用JavaMail API创建最简单邮件(即纯文本邮件)的代码:

public class SimpleMail {
/*
* 简单邮件
*/

public static void main(String[] args) throws Exception {

// 创建邮件
Session session = Session.getDefaultInstance(new Properties()); // session代表与邮件服务器的会话
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("yerenyuan10001@163.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("i_beautifulman@sina.com"));
message.setSubject("love");

message.setContent("hello hello liayun", "text/html");
message.saveChanges();

// 将创建好的邮件写入到C盘以文件的形式进行保存
message.writeTo(new FileOutputStream("c:\\1.eml"));

}

}

运行该程序,我们可以在C盘下看到有生成一个1.eml文件,如要打开该文件,可使用Microsoft Outlook这样的客户端工具,因为Outlook支持后缀名为.eml的文件。由于我本人没安装这样的东西,所以非常遗憾看不了其中的内容了。

创建包含内嵌图片的邮件

使用JavaMail API创建包含内嵌图片的邮件的代码:

public class ImageMail {

public static void main(String[] args) throws Exception {
// 创建邮件
Session session = Session.getDefaultInstance(new Properties()); // session代表与邮件服务器的会话
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("yerenyuan10001@163.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("i_beautifulman@sina.com"));
message.setSubject("love");

// 创建邮件中的数据

// 创建正文
MimeBodyPart text = new MimeBodyPart();
text.setContent("hello liayun<br/><img src='cid:1.jpg'><br/>I love you", "text/html");

// 创建图片
MimeBodyPart image = new MimeBodyPart();
DataHandler dh = new DataHandler(new FileDataSource("src/1.jpg")); // jaf技术
/*
* new一个数据处理器与图片相关联,然后将数据处理器传递给setDataHandler方法,
* 该方法会自动从数据处理器里面获取数据然后弄到image对象中去。
*
* 记住:还要说明这个数据的类型,但是这儿是不需要设置的,因为数据处理器非常聪明,
* 它会自动感知它所关联的数据源的类型,setDataHandler方法除了从数据处理器里面获取数据之外,
* 它还会调用数据处理器的方法来获取它感知的数据类型,帮我们设置好
*/

image.setDataHandler(dh);
image.setContentID("1.jpg"); // 设置ID

// 描述这两部分数据之间的关系
MimeMultipart mm = new MimeMultipart();
mm.addBodyPart(text);
mm.addBodyPart(image);
mm.setSubType("related"); // 描述这两部分数据之间的关系是关联关系

message.setContent(mm); // 设置邮件内容
message.saveChanges(); // 保存邮件

// 将创建好的邮件写入到C盘以文件的形式进行保存
message.writeTo(new FileOutputStream("c:\\1.eml"));
}

}

运行该程序,我们可以在C盘下看到有生成一个1.eml文件。
但我们还有另一种创建包含内嵌图片的邮件的方式,代码如下:

public class ImageMail2 {
/*
* 创建一封带图片的邮件
*/

public static void main(String[] args) throws Exception {
// 创建邮件
Session session = Session.getDefaultInstance(new Properties()); // session代表与邮件服务器的会话
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("yerenyuan10001@163.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("i_beautifulman@sina.com"));
message.setSubject("love");

// message.setContent("hello<br/><img src='c:\\1.jpg'>", "text/html");
message.setContent("hello<br/><img src='http://localhost:8080/mail/1.jpg'>", "text/html");
message.saveChanges();
message.writeTo(new FileOutputStream("c:\\1.eml"));
}

}

但我们一般不推荐这样的做法,这样做容易泄露我们的一些信息,道理我就不详述了,懂的自然懂。

创建包含附件的邮件

使用JavaMail API创建包含附件的邮件的代码:

public class AttachMail {

public static void main(String[] args) throws Exception {
// 创建邮件
Session session = Session.getDefaultInstance(new Properties()); // session代表与邮件服务器的会话
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("yerenyuan10001@163.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("i_beautifulman@sina.com"));
message.setSubject("love");

// 创建封装正文数据的bodypart
MimeBodyPart text = new MimeBodyPart();
text.setContent("hello liayun I love you", "text/html");

// 创建封装附件数据的bodypart
MimeBodyPart attach = new MimeBodyPart();
DataHandler dh = new DataHandler(new FileDataSource("src/1.mp3"));
attach.setDataHandler(dh);
// 只要调用了setFileName方法,JavaMail这套API就会自动帮我们生成Content-Disposition这个头字段
attach.setFileName(dh.getName()); // 通过数据处理器获得附件的附件名,然后再设置附件名

// 描述这两部分数据之间的关系,但正文和附件之间是没关系的,没关系也是一种关系,即mixed
MimeMultipart mm = new MimeMultipart();
mm.addBodyPart(text);
mm.addBodyPart(attach);
mm.setSubType("mixed");

message.setContent(mm);
message.saveChanges();

// 将创建好的邮件写入到C盘以文件的形式进行保存
message.writeTo(new FileOutputStream("c:\\1.eml"));
}

}

运行该程序,我们可以在C盘下看到有生成一个1.eml文件。

包含内嵌图片和附件的复杂邮件

说这样的邮件是世界上最复杂的邮件也不为过,那这样的复杂邮件到底该怎样生成呢?其实也不算多复杂,只要弄懂下面这张图就行了。
邮件原理与JavaMail开发(二)——使用JavaMail创建邮件和发送邮件
使用JavaMail API创建包含内嵌图片和附件的复杂邮件的代码:

public class ComplexMail {
/*
* 世界上最复杂的邮件
*/

public static void main(String[] args) throws Exception {
// 创建邮件
Session session = Session.getDefaultInstance(new Properties()); // session代表与邮件服务器的会话
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("yerenyuan10001@163.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("i_beautifulman@sina.com"));
message.setSubject("love");

// 创建bodypart封装正文
MimeBodyPart text = new MimeBodyPart();
text.setContent("hello, hello, liayun<img src='cid:1.jpg'>", "text/html");

// 创建bodypart封装图片
MimeBodyPart image = new MimeBodyPart();
image.setDataHandler(new DataHandler(new FileDataSource("src/1.jpg")));
image.setContentID("1.jpg");

// 创建bodypart封装附件
MimeBodyPart attach = new MimeBodyPart();
DataHandler dh = new DataHandler(new FileDataSource("src/1.mp3"));
attach.setDataHandler(dh);

// 只要调用了setFileName方法,它就会自动帮你生成Content-Disposition这个头字段
attach.setFileName(dh.getName());

// 描述数据关系
MimeMultipart content = new MimeMultipart();
content.addBodyPart(text);
content.addBodyPart(image);
content.setSubType("related");

MimeBodyPart mbp = new MimeBodyPart();
mbp.setContent(content);

MimeMultipart mm = new MimeMultipart();
mm.addBodyPart(mbp);
mm.addBodyPart(attach);
mm.setSubType("mixed");

message.setContent(mm);
message.saveChanges();

// 将创建好的邮件写入到C盘以文件的形式进行保存
message.writeTo(new FileOutputStream("c:\\1.eml"));
}

}

运行该程序,我们可以在C盘下看到有生成一个1.eml文件。

中文名的邮件附件的乱码问题

我们中国人编写程序真的很麻烦,每学完一个新的技术,就要考虑中文乱码问题,现在我们就要开始考虑这个问题了。我们就以使用JavaMail API创建包含内嵌图片和附件的复杂邮件为例,来说明创建邮件中的一些中文乱码问题。按照咱中国人的习惯,创建一封邮件时,有可能邮件的主题是中文,邮件的正文也是中文,邮件所带的附件的名字同样也是中文,如下:

public class ComplexMail {
/*
* 世界上最复杂的邮件
*/

public static void main(String[] args) throws Exception {
// 创建邮件
Session session = Session.getDefaultInstance(new Properties()); // session代表与邮件服务器的会话
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("yerenyuan10001@163.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("i_beautifulman@sina.com"));
message.setSubject("我爱你,那个人");

// 创建bodypart封装正文
MimeBodyPart text = new MimeBodyPart();
text.setContent("我是真的爱你,你知道吗?<img src='cid:1.jpg'>", "text/html");

// 创建bodypart封装图片
MimeBodyPart image = new MimeBodyPart();
image.setDataHandler(new DataHandler(new FileDataSource("src/1.jpg")));
image.setContentID("1.jpg");

// 创建bodypart封装附件
MimeBodyPart attach = new MimeBodyPart();
DataHandler dh = new DataHandler(new FileDataSource("src/爱的秘密蓝调口琴曲.mp3"));
attach.setDataHandler(dh);
// 只要调用了setFileName方法,它就会自动帮你生成Content-Disposition这个头字段
attach.setFileName(dh.getName());

// 描述数据关系
MimeMultipart content = new MimeMultipart();
content.addBodyPart(text);
content.addBodyPart(image);
content.setSubType("related");

MimeBodyPart mbp = new MimeBodyPart();
mbp.setContent(content);

MimeMultipart mm = new MimeMultipart();
mm.addBodyPart(mbp);
mm.addBodyPart(attach);
mm.setSubType("mixed");

message.setContent(mm);
message.saveChanges();

message.writeTo(new FileOutputStream("c:\\1.eml"));
}

}

运行该程序,我们可以在C盘下看到有生成一个1.eml文件。如果我们使用Microsoft Outlook这样的客户端工具打开这个文件,会发现:

  • 邮件主题显示正常,没有出现中文乱码问题
  • 邮件正文显示为乱七八糟的东西,出现中文乱码问题
  • 邮件的附件名也显示为乱七八糟的东西,出现中文乱码问题

这时,到底该怎么解决呢?解决代码如下:

public class ComplexMail {
/*
* 世界上最复杂的邮件
*/

public static void main(String[] args) throws Exception {
// 创建邮件
Session session = Session.getDefaultInstance(new Properties()); // session代表与邮件服务器的会话
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("yerenyuan10001@163.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("i_beautifulman@sina.com"));
message.setSubject("我爱你,那个人");

// 创建bodypart封装正文
MimeBodyPart text = new MimeBodyPart();
text.setContent("我是真的爱你,你知道吗?<img src='cid:1.jpg'>", "text/html;charset=UTF-8");

// 创建bodypart封装图片
MimeBodyPart image = new MimeBodyPart();
image.setDataHandler(new DataHandler(new FileDataSource("src/1.jpg")));
image.setContentID("1.jpg");

// 创建bodypart封装附件
MimeBodyPart attach = new MimeBodyPart();
DataHandler dh = new DataHandler(new FileDataSource("src/爱的秘密蓝调口琴曲.mp3"));
attach.setDataHandler(dh);
// System.out.println(dh.getName()); // 数据处理器获取附件名时没有中文乱码问题,显示正常

// 只要调用了setFileName方法,它就会自动帮你生成Content-Disposition这个头字段
attach.setFileName(MimeUtility.encodeText(dh.getName())); // 设置附件名的时候出现中文乱码问题了,该怎么解决呢?

// 描述数据关系
MimeMultipart content = new MimeMultipart();
content.addBodyPart(text);
content.addBodyPart(image);
content.setSubType("related");

MimeBodyPart mbp = new MimeBodyPart();
mbp.setContent(content);

MimeMultipart mm = new MimeMultipart();
mm.addBodyPart(mbp);
mm.addBodyPart(attach);
mm.setSubType("mixed");

message.setContent(mm);
message.saveChanges();

message.writeTo(new FileOutputStream("c:\\1.eml"));
}

}

这样,我们在使用JavaMail API创建不管什么类型的邮件时,所有与中文乱码相关的问题都已解决,大家可以放心大胆地创建邮件了。

使用JavaMail API发送邮件

邮件收发 API 的体系结构:
邮件原理与JavaMail开发(二)——使用JavaMail创建邮件和发送邮件
JavaMail API按其功能划分通常可分为如下三大类:

  • 创建和解析邮件内容的API:Message类是创建和解析邮件的核心API,它的实例对象代表一封电子邮件。
  • 发送邮件的API:Transport类是发送邮件的核心API类,它的实例对象代表实现了某个邮件发送协议的邮件发送对象,例如SMTP协议。
  • 接收邮件的API:Store类是接收邮件的核心API类,它的实例对象代表实现了某个邮件接收协议的邮件接收对象,例如POP3协议。

邮件发送 API 的体系结构

JavaMail API中定义了一个java.mail.Transport类,它专门用于执行邮件发送任务,这个类的实例对象封装了某种邮件发送协议的底层实施细节,应用程序调用这个类中的方法就可以把Message对象中封装的邮件数据发送到指定的SMTP服务器。使用JavaMail发送邮件是涉及到的主要API之间的工作关系如图所示:
邮件原理与JavaMail开发(二)——使用JavaMail创建邮件和发送邮件
图中的各个类的功能及相互关系如下:

  1. 从Session对象中获得实现了某种邮件发送协议的Transport对象。
  2. 使用Session对象创建Message对象,并调用Message对象的方法封装邮件数据。
  3. 连接指定的SMTP服务器,调用Transport对象中的邮件发送方法发送Message对象中封装的邮件数据。

Session类

mail.jar包中的javax.mail.Session类用于定义整个JavaMail应用程序所需的环境信息,以及收集客户端与邮件服务器建立网络连接的会话信息,如邮件服务器的主机名、端口号、采用的邮件发送和接收协议等。Session对象根据这些信息构建用于邮件收发的Transport和Store对象,以及为客户端创建Message对象时提供信息支持。下面是Session类中定义的常用方法。

getInstance与getDefaultInstance方法

getInstance和getDefaultInstance是Session类中的静态方法,它们都可用于获得Session类的实例对象。由于Session类的构造函数是私有的,所以,应用程序必须调用getInstance或getDefaultInstance静态方法获得Session类的实例对象。getInstance方法和getDefaultInstance方法各有两种重载形式,它们的语法定义如下:

  • public static Session getInstance(java.util.Properties props)
  • public static Session getInstance(java.util.Properties props, Authenticator authenticator)
  • public static Session getDefaultInstance(java.util.Properties props)
  • public static Session getDefaultInstance(java.util.Properties props, Authenticator authenticator)

getInstance方法与getDefaultInstance方法的区别在于:getDefaultInstance方法返回一个Session对象后,将把这个Session对象安装为缺省的Session对象,以后每次调用getDefaultInstance方法都将返回这个缺省Session对象;而getInstance方法则是每次调用都返回一个新的Session对象。只要掌握了getInstance方法的应用,自然也就掌握了getDefaultInstance方法的应用,所以下面只以getInstance方法为例进行讲解。
两个重载的getInstance方法都接收一个Properties对象作为参数,Properties对象中保存了实例化Session对象所需的应用程序环境信息,以及客户端与邮件服务器建立连接所必须的会话信息。这些信息被称为JavaMail属性,它们的属性名作为Properties对象的关键字进行保存。表中列出了一些常用的JavaMail连接属性,更多的属性可以查看JavaMail规范文档中的附录A部分和各种协议的服务实现程序的有关文档。

JavaMail属性 描述
mail.smtp.host 指定连接的邮件服务器主机名
mail.transport.protocol 指定采用的邮件发送协议
mail.store.protocol 指定采用的邮件接收协议
mail.smtp.auth 指定客户端是否向邮件服务器提交认证

第二个getInstance方法除了接收一个Properties类型的参数外,还接收一个Authenticator对象作为参数。Authenticator主要用于提供用户认证信息,调用第二个getInstance方法创建Session对象时,将把作为第二个参数传入的Authenticator对象注册到该Session对象中。以后,使用这个Session对象的JavaMail客户端程序要向邮件服务器提交认证信息时,将调用该Session对象中注册的Authenticator对象,从中获得用户认证信息后传递给邮件服务器。

邮件发送程序

我们先使用JavaMail API发送一封简单的邮件,步骤为

  • 创建包含邮件服务器的网络连接信息的Session对象。
  • 创建代表邮件内容的Message对象。
  • 创建Transport对象、连接服务器、发送Message、关闭连接。

这样使用JavaMail API发送一封最简单的邮件(纯文本邮件)的代码为:

public class SendMail {

public static void main(String[] args) throws Exception {

Properties prop = new Properties();
prop.setProperty("mail.smtp.host", "smtp.163.com");
prop.setProperty("mail.transport.protocol", "smtp");
prop.setProperty("mail.smtp.auth", "true");

Session session = Session.getInstance(prop); // 创建出与指定邮件服务器会话的session
/*
* 为了看清javamail这套API到底是如何向服务器发邮件的,可以把session的Debug开关打开,
* 把这个调试开关打开,javamail这套API会把它与服务器的交互过程打印在命令行窗口
*/

session.setDebug(true);
Message message = createMessage(session);

Transport ts = session.getTransport();
ts.connect("yerenyuan10001", "邮箱登录密码"); // 连接上邮件服务器,其内部会自动帮你进行base64编码
ts.sendMessage(message, message.getAllRecipients()); // 向谁发送一封邮件
ts.close(); // 断开与服务器的连接
}

private static Message createMessage(Session session) throws AddressException, MessagingException, UnsupportedEncodingException {
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("yerenyuan10001@163.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("i_beautifulman@sina.com"));
message.setSubject("love");

message.setContent("hello hello liayun", "text/html");
message.saveChanges();
return message;
}

}

提示:创建出包含邮件服务器的网络连接信息的Session对象之后,为了看清JavaMail这套API到底是如何向邮件服务器发送邮件的,可以把session的Debug开关打开,把这个调试开关打开后,JavaMail这套API会把它与邮件服务器的交互过程打印在Eclipse的控制台上。
运行以上程序,然后登陆到i_beautifulman@sina.com邮箱当中,就可以收取到由yerenyuan10001@163.com发送的Email了,如下图所示:
邮件原理与JavaMail开发(二)——使用JavaMail创建邮件和发送邮件
接着我们使用JavaMail API发送一封复杂邮件,如下:

public class SendMail {

public static void main(String[] args) throws Exception {

Properties prop = new Properties();
prop.setProperty("mail.smtp.host", "smtp.163.com");
prop.setProperty("mail.transport.protocol", "smtp");
prop.setProperty("mail.smtp.auth", "true");

Session session = Session.getInstance(prop); // 创建出与指定邮件服务器会话的session
/*
* 为了看清javamail这套API到底是如何向服务器发邮件的,可以把session的Debug开关打开,
* 把这个调试开关打开,javamail这套API会把它与服务器的交互过程打印在命令行窗口
*/

session.setDebug(true);
Message message = createMessage(session);

Transport ts = session.getTransport();
ts.connect("yerenyuan10001", "邮箱登录密码"); // 连接上邮件服务器,其内部会自动帮你进行base64编码
ts.sendMessage(message, message.getAllRecipients()); // 向谁发送一封邮件
ts.close(); // 断开与服务器的连接
}

private static Message createMessage(Session session) throws AddressException, MessagingException, UnsupportedEncodingException {
// 创建邮件
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("yerenyuan10001@163.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("i_beautifulman@sina.com"));
message.setSubject("我爱你,那个人");

// 创建bodypart封装正文
MimeBodyPart text = new MimeBodyPart();
text.setContent("我是真的爱你,你知道吗?<img src='cid:1.jpg'>", "text/html;charset=UTF-8");

// 创建bodypart封装图片
MimeBodyPart image = new MimeBodyPart();
image.setDataHandler(new DataHandler(new FileDataSource("src/1.jpg")));
image.setContentID("1.jpg");

// 创建bodypart封装附件
MimeBodyPart attach = new MimeBodyPart();
DataHandler dh = new DataHandler(new FileDataSource("src/爱的秘密蓝调口琴曲.mp3"));
attach.setDataHandler(dh);
// System.out.println(dh.getName()); // 数据处理器获取附件名时没有中文乱码问题,显示正常

// 只要调用了setFileName方法,它就会自动帮你生成Content-Disposition这个头字段
attach.setFileName(MimeUtility.encodeText(dh.getName())); // 设置附件名的时候出现中文乱码问题了,该怎么解决呢?

// 描述数据关系
MimeMultipart content = new MimeMultipart();
content.addBodyPart(text);
content.addBodyPart(image);
content.setSubType("related");

MimeBodyPart mbp = new MimeBodyPart();
mbp.setContent(content);

MimeMultipart mm = new MimeMultipart();
mm.addBodyPart(mbp);
mm.addBodyPart(attach);
mm.setSubType("mixed");

message.setContent(mm);
message.saveChanges();

return message;
}

}

运行以上程序,然后登陆到i_beautifulman@sina.com邮箱当中,就可以收取到由yerenyuan10001@163.com发送的Email了,如下图所示:
邮件原理与JavaMail开发(二)——使用JavaMail创建邮件和发送邮件
将附件爱的秘密蓝调口琴曲.mp3下载下来,并且能成功播放。