一、快速入门
1.1 介绍
在线发送、接收邮件,目前是企业应用系统开发中的通用功能需求,例如,在线投递通知、激活账户、发送和用户注册相关的信息等。Apache Commons Email 是 Apache 提供的一个开源的API,是基于 JavaMail API 而构建的一套用 Java 操作邮件系统的工具类库。其提供了常用的邮件发送和接收类,对 JavaMail API进行了封装,从而简化其操作,使用起来非常方便。
我们可以在官网网站 http://commons.apache.org/email 中下载与邮件系统有关的 Commons Email 组件的系统库文件 commons-email。Commons Email 组件依赖于标准的 JavaMail API 类库,还需要下载与 JavaMail API 有关的系统库文件。相关依赖如下所示:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.5.6</version>
</dependency>
1.2 关键对象
Apache commons email l的核心是Email类,它是一个抽象类,提供了发送邮件的核心功能。具体有以下几个实现类:
实现类 | 说明 |
---|---|
SimpleEmail | 发送简单邮件,即纯文本邮件 |
MultiPartEmail | 发送带附件的邮件 |
HtmlEmail | 发送超文本邮件 |
ImageHtmlEmail | 发送图文混排的超文本邮件 |
EmailAttachment |
下面是Email的类图
通过类图可以看到很多额外信息:
- HtmlEmail 继承了 MultiPartEmail,说明它也同时支持附件。
- ImageHtmlEmail 继承了 HtmlEmail,说明它也同时支持附件和超文本。
二、常用功能类的应用
2.1 Email
抽象类 Email 及其主要功能方法说明,如下表所示:
方法 | 说明 |
---|---|
addBcc(String email) | |
addCc(String email) | |
addReplyTo(String email) | |
addTo(String email) | 设置收件人邮箱 |
isSendPartial() | |
isSSLOnConnect() | |
send() | 发送邮件 |
sendMimeMessage() | |
setAuthentication(String userName,String password) | SMTP服务器进行身份验证,用户名和密码为邮箱的账号和授权码 |
setBounceAddress(String email) | |
setCharset(String charset) | 设置邮件的字符集编码 |
setContent(MimeMultipart mimeMultipart) | |
setContent(Object obj, String contentType) | |
setDebug(boolean d) | 是否激活任何邮件类的调试 |
setFrom(String email) | 设置发件人邮箱 |
setHostName(String hostName) | 设置使用发电子邮件的邮件服务器 |
setMsg(String msg) | 设置邮件正文内容。 该方法为抽象方法,需要在子类中被重写 |
setSendPartial(boolean sendPartial) | |
setSentDate(Date date) | |
setSmtpPort(int portNumber) | 邮件服务器smtp协议的SSL端口 |
setSocketTimeout(int socketTimeout) | |
setSSLOnConnect(boolean ssl) | 设置SSL安全连接 |
setSubject(String subject) | 设置邮件主题 |
2.2 SimpleEmail
利用该类可以实现发送简单的文本类型的邮件,并利用 SimpleEmail 类中的设置邮件内容的方法 setMsg 定义邮件正文内容。注意: SimpleEmail 只能发送文本类型的邮件,并且不能带附件。
方法 | 说明 |
---|---|
2.3 MultiPartEmail
EmailAttachment 类知识包装邮件的附件,如果真正要实现发送带附件文件的邮件,此时应该选择 MultiPartEmail 类作为对邮件内容的包装,因为 MultiPartEmail 类提供了有将附件文件添加到邮件体中的各个功能方法。下面为 MultiPartEmail 类中的主要功能方法的定义,如下表所示:
方法 | 说明 |
---|---|
addPart(MimeMultipart multipart) | |
addPart(MimeMultipart multipart, int index) | |
addPart(String partContent, String partContentType) | |
MultiPartEmail attach(DataSource ds,String name,String description) | |
attach(DataSource ds,String name,String description,String disposition) | |
attach(EmailAttachment attachment) | |
attach(File file) | |
attach(URL url, String name, String description) | |
attach(URL url,String name,String description,String disposition) |
2.4 HtmlEmail
HtmlEmail 类为开发人员提供发送 HTML 格式的邮件内容,利用 HtmlEmail 类中的 setHtmlMsg 方法可以设置 HTML 格式的邮件正文内容,而利用 setTextMsg 方法可以设置文本格式的邮件正文内容,可以根据邮件正文内容格式的具体需要进行选择。
方法 | 说明 |
---|---|
2.5 ImageHtmlEmail
ImageHtmlEmail类通常是用来发送Html格式并内嵌图片的邮件,拥有所有HtmlEmail的功能,但是图片主要是以html内嵌的为主
2.6 EmailAttachment
利用该类可以实现发送带附件的邮件,并利用它实现对邮件的附件文件进行包装,主要有下面几种常用的方法:
方法 | 说明 |
---|---|
setDescription(String desc) | 设置附件描述,能够随便写 |
setDisposition(String disposition) | 表示点击附件是否需要直接打开或者以附件形式下载 |
setName(String name) | 附件名,注意和文件格式一致,这将是接收人下载下来的文件名称。 如果附件是中文名会在乱码,通过 MimeUtility.encodeText 转码 |
setPath(String path) | 指定附件在本地的绝对路径 |
setURL(URL url) | 设置网络附件的URL |
三、使用介绍
3.1 邮箱设置
想要通过程序发送邮件,首先需要有一个邮箱做为发件人,并开启POP3/SMTP服务,获取对应邮箱的授权码,不同的邮箱开启方式和位置不甚相同,以下以163邮箱和QQ邮箱为例说明,其余邮箱可以自行搜索开启方式。
- 163邮箱
进入邮箱首页,点击设置,选择下拉选项的“POP3/SMTP/IMAP”,点击进入 POP3/SMTP/IMAP 部分 ,点击“POP3/SMTP服务”后的【开启】,弹出页面,用绑定手机扫码发送短信,发送完毕后可获得授权码。
- QQ邮箱
进入邮箱首页,点击设置,切换到账户页签,将页面滑动到“POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 ”部分,点击“POP3/SMTP服务”后的【开启】,会弹出页面提醒用QQ绑定的手机号发送短信,发送完毕后,点击“我已发送”,即可获得授权码。
3.2 简单邮件
简单邮件就是纯文本邮件,格式简单,下面看看使用Commons-Email的API的例子,示例代码如下所示:
/**
* 发送内容为简单文本的邮件
*/
public static void sendSimpleTextEmail() throws EmailException {
Email email = new SimpleEmail();
email.setHostName(MAIL_SERVER_HOST);
email.setSmtpPort(25);
email.setAuthenticator(new DefaultAuthenticator(MAIL_SERVER_USER, MAIL_SERVER_PASSWORD));
email.setSSLOnConnect(true);
email.setDebug(DEBUG_MODE);
email.setCharset("UTF-8");
email.setFrom(MAIL_SERVER_USER, NICK_NAME);
email.addTo("duleilewuhen@sina.com");
email.setSubject("测试邮件");
email.setMsg("这是一封简单的邮件This is the third test mail ... :-)");
email.send();
}
注意:Email 实例对象的 setHostName 的显示调用设置将用于发送邮件的传出SMTP服务器的地址,如果没有设置,将从系统属性 mail.host 中获得。
3.3 带附件的电子邮件
发送包含附件的邮件,这里用到了一个 EmailAttachment 对象,也就是附件的意思
/**
* 发送包含附件的邮件(附件为本地资源)
*/
public static void sendEmailsWithAttachment() throws EmailException, UnsupportedEncodingException {
// 建立一个attachment(附件)对象
EmailAttachment attachment = new EmailAttachment();
attachment.setPath("/Users/dllwh/Desktop/redis.sh");
attachment.setDisposition(EmailAttachment.ATTACHMENT);
attachment.setDescription("Picture");
attachment.setName(MimeUtility.encodeText(" 测试 "));
// 由于要上传附件,因此用MultiPartEmail()方法建立一个email对象
MultiPartEmail email = new MultiPartEmail();
email.setHostName(MAIL_SERVER_HOST);
email.setAuthentication(MAIL_SERVER_USER, MAIL_SERVER_PASSWORD);
email.setFrom(MAIL_SERVER_USER, NICK_NAME);
email.addTo("duleilewuhen@sina.com");
email.setSubject("测试邮件");
email.setMsg("测试邮件的正文内容!");
email.setCharset("UTF-8");
// 将附件添加到邮件
email.attach(attachment);
email.send();
}
发送包含附近的邮件(附件为在线资源),这个与上传本地附件稍有区别,注意一下就行
/**
* 发送包含附件的邮件(附件为在线资源,在发送时自动将网络上资源下载发送)
*/
public static void sendEmailsWithOnlineAttachment() throws MalformedURLException, EmailException {
EmailAttachment attachment = new EmailAttachment();
// 设置在线资源路径,和上传本地附件的惟一区别
attachment.setURL(new URL("https://www.apache.org/images/asf_logo_wide.gif"));
attachment.setDisposition(EmailAttachment.ATTACHMENT);
attachment.setDescription("Apache logo");
attachment.setName("Apache logo.gif");
MultiPartEmail email = new MultiPartEmail();
email.setHostName(MAIL_SERVER_HOST);
email.setAuthentication(MAIL_SERVER_USER, MAIL_SERVER_PASSWORD);
email.setFrom(MAIL_SERVER_USER, NICK_NAME);
email.addTo("duleilewuhen@sina.com");
email.setSubject("测试邮件");
email.setMsg("发送的图片是一个网站的logo");
email.attach(attachment);
email.send();
}
3.4 HTML格式的邮件
发送内容为HTML格式的邮件,有些邮件直接打开就是一个HTML页面。虽然不必定用到,能够了解一下。发送HTML格式的电子邮件是通过使用 HtmlEmail 类来完成的,该类的工作方式与 MultiPartEmail 类完全相同,其中包括用于设置html内容的方法,如果收件人不支持HTML电子邮件,则添加替代文本内容,并添加内嵌图像。
/**
* 发送内容为HTML格式的邮件,内嵌图片
*/
public static void sendHtmlMailWithImage() throws EmailException, MalformedURLException {
HtmlEmail email = new HtmlEmail();
email.setHostName(MAIL_SERVER_HOST);
email.addTo("duleilewuhen@sina.com");
email.setFrom(MAIL_SERVER_USER, NICK_NAME);
email.setSubject("Test email with inline image");
email.setAuthenticator(new DefaultAuthenticator(MAIL_SERVER_USER, MAIL_SERVER_PASSWORD));
email.setCharset("UTF-8");
// 图片的网络地址
URL url = new URL("https://www.apache.org/images/asf_logo_wide.gif");
// 该字符串是随机生成的标识符,必须用于引用图像标签中的图像。
String cid = email.embed(url, "Apache logo");
// 将图片引入html标签
email.setHtmlMsg("<html>The apache logo - <img src=\"cid:" + cid + "\"></html>");
// 额外提示
email.setTextMsg("您的邮件不支持html格式");
email.send();
}
从上面示例中,可以看出HtmlEmail其实也可以发送图片,那ImageHtmlEmail存在的意义是什么呢?其实HtmlEmail发送图片都需要调用其embed方法,并将其返回值设置到 <img> 标签的src上,示例如下:
// embed方法有多个重载方法,支持URL,本地文件等
String cid = email.embed(new File("D:\\commons mail\\images\\5.jpg"));
email.setHtmlMsg("<html><img src=\"cid:" + cid + "\"></html>");
如果在我们的电子邮箱中,使用的内嵌图数量很少时,可以使用上面的方式。但是如果是大量的内嵌在线图片时,我们可以通过使用 ImageHtmlEmail 来解决每次输入全路径的URL问题。
/**
* 发送内容为HTML格式的邮件,内嵌图片
*/
public void sendHtmlMailWithImageByDataSource() throws MalformedURLException, EmailException {
ImageHtmlEmail email = new ImageHtmlEmail();
email.setHostName(MAIL_SERVER_HOST);
email.setSmtpPort(456);
email.setSSLOnConnect(true);
email.setAuthentication(MAIL_SERVER_USER, MAIL_SERVER_PASSWORD);
email.setFrom(MAIL_SERVER_USER, NICK_NAME);
email.addTo("duleilewuhen@sina.com");
email.setCharset("UTF-8");
email.setSubject("测试邮件");
URL url = new URL("https://www.baidu.com");
// 这样HTML内容里如果有此路径下的图片会直接内联
email.setDataSourceResolver(new DataSourceUrlResolver(url));
String htmlEmail = "这里<img src='https://www.baidu.com/img/bd_logo1.png'>有图片。";
email.setHtmlMsg(htmlEmail);
// 额外提示
email.setTextMsg("你的邮件客户端不支持html邮件");
email.send();
}
说明:我们创建一个引用一些图像的HTML电子邮件模板,所有引用的图像都通过指定的DataSourceResolver自动转换为内嵌图像。这里用到了DataSourceFileResolver对象,和DataSourceUrlResolver对象,前者能够解析本地文件路径,后者能够解析网络路径。
四、注意事项
4.1 公网邮箱安全参数
我们在客户端设置邮箱或者 JavaMail 编程的时候,我们都会去查找这些公网邮箱的 IMAP/SMTP/POP3 地址,这里总结了主流的邮件服务商关于IMAP/SMTP/POP3 地址和端口的参数设置。
-
Gmail
服务器名称 服务器地址 SSL协议端口 非SSL协议端口 IMAP imap.gmail.com 993 / SMTP smtp.gmail.com 465 / POP3 pop.gmail.com 995 / -
QQ邮箱
服务器名称 服务器地址 SSL协议端口 非SSL协议端口 IMAP imap.qq.com 993 143 SMTP smtp.qq.com 465或587 25 POP3 pop.qq.com 995 110 -
163邮箱
服务器名称 服务器地址 SSL协议端口 非SSL协议端口 IMAP imap.163.com 993 143 SMTP smtp.163.com 465或994 25 POP3 pop.163.com 995 110 -
阿里云邮箱
服务器名称 服务器地址 SSL协议端口 非SSL协议端口 IMAP imap.aliyun.com 993 143 SMTP smtp.aliyun.com 465 25 POP3 pop.aliyun.com 995 110 -
微软outlook邮箱
服务器名称 服务器地址 SSL协议端口 非SSL协议端口 IMAP pod51003.outlook.com 993 / SMTP pod51003.outlook.com / 587 POP3 pod51003.outlook.com 995 /
4.2 邮箱授权码介绍
一些邮箱的服务商为了用户的使用安全推出了授权码,用于做为登录第三方客户端的专用密码。一般在邮箱账号的设置项中有开POP3、IMAP、SMTP、Exchange等服务,然后通过平台验证就会获取该邮箱账号的授权码。这里以QQ邮箱获取授权码为例子介绍下,这里以开启IMAP/SMTP服务为例子:
通过QQ的密密保验证后,我们可以看到下方的授权码
然后在我们的程序中将该授权码当做密码使用即可。
五、总结
Commons Email 做为Java发送电子邮件的工具类,API简单易懂,大大简化了Java邮件发送程序的复杂度,用来代替Java自带的API是不错的选择。