实际开发中电子邮件的应用非常广泛,比如注册激活邮件,邮件找回密码,自动批量发送活动信息等。本文介绍如何通过 Java 代码来创建支持附件、支持多收件人、多抄送人、多密送人的复杂电子邮件,并连接邮件服务器发送邮件。
电子邮件协议
常用的电子邮件协议包括 SMTP,POP3,IMAP,其中邮件的创建和发送只需要用到 SMTP协议,所以代码也只涉SMTP协议,SMTP 是 Simple Mail Transfer Protocol 的简称,即简单邮件传输协议。
JavaMail
Java 官方也提供了对电子邮件协议封装的 Java 类库JavaMail,自行官网下载。
mvn项目的话,添加依赖如下:
<!-- JavaMail邮件发送 -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.5.0-b01</version>
</dependency>
创建一封电子邮件的步骤:
1. 创建一个邮件对象(MimeMessage)并链接到邮件服务器;
2. 设置发件人、收件人(可多个收件人、抄送人、密送人)、邮件的主题(标题)、正文(内容)、显示的发送时间;
3. 发送。
准备工作:
发送邮件首先需要有一个邮箱账号和密码,本文以qq邮箱为例,邮箱账号必须要开启 SMTP 服务,在浏览器网页登录邮箱后一般在邮箱的“设置”选项中可以开启,并记下授权码,如下所示(其他邮箱大同小异):
实现代码如下:
实体类EmailBean.java:
package com.liberal.common.bean.email;
import com.liberal.common.bean.email.EmailUser;
import java.util.List;
/**
* @author weny.yang
* @ClassName: EmailBean
* @Description:邮件实体
* @date Nov 2, 2020
*/
public class EmailBean {
private String smtpHost;// 发件人邮箱的 SMTP 服务器地址
private EmailUser fromUser;// 发件人
private List<EmailUser> recipientType_TO;//(必填) 收件人,可以配置多个
private List<EmailUser> recipientType_CC;//(可选) 抄送人,可以配置多个
private List<EmailUser> recipientType_BCC;//(可选) 密送人,可以配置多个,其他人无法知道密送人收到邮件
private String emailTitle;// 邮件主题
private String emailContent;// 邮件内容
private List<String> annexPaths;// 附件路径
public EmailBean() {
super();
}
public EmailBean(String smtpHost, EmailUser fromUser, List<EmailUser> recipientType_TO, List<EmailUser> recipientType_CC,
List<EmailUser> recipientType_BCC, String emailTitle, String emailContent, List<String> annexPaths) {
super();
this.smtpHost = smtpHost;
this.fromUser = fromUser;
this.recipientType_TO = recipientType_TO;
this.recipientType_CC = recipientType_CC;
this.recipientType_BCC = recipientType_BCC;
this.emailTitle = emailTitle;
this.emailContent = emailContent;
this.annexPaths = annexPaths;
}
public String getSmtpHost() {
return smtpHost;
}
public void setSmtpHost(String smtpHost) {
this.smtpHost = smtpHost;
}
public EmailUser getFromUser() {
return fromUser;
}
public void setFromUser(EmailUser fromUser) {
this.fromUser = fromUser;
}
public List<EmailUser> getRecipientType_TO() {
return recipientType_TO;
}
public void setRecipientType_TO(List<EmailUser> recipientType_TO) {
this.recipientType_TO = recipientType_TO;
}
public List<EmailUser> getRecipientType_CC() {
return recipientType_CC;
}
public void setRecipientType_CC(List<EmailUser> recipientType_CC) {
this.recipientType_CC = recipientType_CC;
}
public List<EmailUser> getRecipientType_BCC() {
return recipientType_BCC;
}
public void setRecipientType_BCC(List<EmailUser> recipientType_BCC) {
this.recipientType_BCC = recipientType_BCC;
}
public String getEmailTitle() {
return emailTitle;
}
public void setEmailTitle(String emailTitle) {
this.emailTitle = emailTitle;
}
public String getEmailContent() {
return emailContent;
}
public void setEmailContent(String emailContent) {
this.emailContent = emailContent;
}
public List<String> getAnnexPaths() {
return annexPaths;
}
public void setAnnexPaths(List<String> annexPaths) {
this.annexPaths = annexPaths;
}
public String toString() {
return "{smtpHost=" + smtpHost + ",fromUser=" + fromUser + ",recipientType_TO=" + recipientType_TO
+ ",recipientType_CC=" + recipientType_CC + ",recipientType_BCC=" + recipientType_BCC + ",emailTitle="
+ emailTitle + ",emailContent=" + emailContent + ",annexPaths = " + annexPaths + "}";
}
}
实体类EmailUser.java:
package com.liberal.common.bean.email;
/**
* @author weny.yang
* @ClassName: User
* @Description:发件人/收件人/抄送人/密送人
* @date 2020年11月10日
*/
public class EmailUser {
private String name;// 昵称
private String address;// 邮箱地址
private String authCode;// 授权码(发件人需要,收件人/抄送人/密送人不需要)
/**
* 构造函数 User.发件人
*/
public EmailUser(String name, String address, String authCode) {
super();
this.name = name;
this.address = address;
this.authCode = authCode;
}
/**
* 构造函数 User.收件人/抄送人/密送人
*/
public EmailUser(String address) {
super();
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getAuthCode() {
return authCode;
}
public void setAuthCode(String authCode) {
this.authCode = authCode;
}
public String toString() {
return "{name=" + name + ",address=" + address + "}";
}
}
工具类:
package com.liberal.common.utils.email;
import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import com.liberal.common.bean.email.EmailBean;
import com.liberal.common.bean.email.EmailUser;
import lombok.extern.slf4j.Slf4j;
import com.sun.mail.util.MailSSLSocketFactory;
/**
* @author weny.yang
* @ClassName: EmailUtil
* @Description:复杂邮件发送工具,支持附件
* @date 2020年11月9日
*/
@Slf4j
public class EmailUtil {
/**
* @Title: sendEmail
* @Description:发送复杂邮件
* @author weny.yang
*/
public static void sendEmail(EmailBean bean) {
Transport transport = null;
try {
log.info("发送邮件开始[" + bean.getEmailTitle() + "]");
Properties prop = new Properties();
prop.setProperty("mail.host", bean.getSmtpHost()); // 邮件服务器
prop.setProperty("mail.transport.protocol", "smtp"); // 邮件发送协议
prop.setProperty("mail.smtp.auth", "true"); // 需要验证用户名密码
// SSL加密
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable", "true");
prop.put("mail.smtp.ssl.socketFactory", sf);
// 1、创建应用程序所需的环境会话 session 对象
Session session = Session.getDefaultInstance(prop, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
// 发件人的邮箱地址和授权码
return new PasswordAuthentication(bean.getFromUser().getAddress(), bean.getFromUser().getAuthCode());
}
});
// 2、获取 transport 对象
transport = session.getTransport();
// 3、连接邮箱服务器
transport.connect(bean.getSmtpHost(), bean.getFromUser().getAddress(), bean.getFromUser().getAuthCode());
// 4、创建复杂邮件
MimeMessage mimeMessage = creatComplexEmail(session, bean);
// 5、发送邮件
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
log.info("发送邮件完成[" + bean.getEmailTitle() + "]");
} catch (Exception e) {
log.error("邮件发送异常", e);
} finally {
try {
if (null != transport) {
// 6、关闭连接
transport.close();
}
} catch (MessagingException e) {
log.error("资源释放异常", e);
}
}
}
/**
* @Title: complexEmail
* @Description:创建复杂邮件
* @author weny.yang
*/
private static MimeMessage creatComplexEmail(Session session, EmailBean bean) throws Exception {
// 消息信息
MimeMessage message = new MimeMessage(session);
// 发件人
message.setFrom(new InternetAddress(bean.getFromUser().getAddress(), bean.getFromUser().getName(), "UTF-8"));
// 收件人
List<EmailUser> toList = bean.getRecipientType_TO();
if (toList != null && toList.size() > 0) {
for (EmailUser user : toList) {
message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(user.getAddress(), user.getName(), "UTF-8"));
}
}
// 抄送人
List<EmailUser> ccList = bean.getRecipientType_CC();
if (ccList != null && ccList.size() > 0) {
for (EmailUser user : ccList) {
message.setRecipient(MimeMessage.RecipientType.CC, new InternetAddress(user.getAddress(), user.getName(), "UTF-8"));
}
}
// 密送人
List<EmailUser> bccList = bean.getRecipientType_BCC();
if (bccList != null && bccList.size() > 0) {
for (EmailUser user : bccList) {
message.setRecipient(MimeMessage.RecipientType.BCC, new InternetAddress(user.getAddress(), user.getName(), "UTF-8"));
}
}
// 邮件标题
message.setSubject(bean.getEmailTitle());
// 邮件文本
MimeBodyPart text = new MimeBodyPart();
text.setContent(bean.getEmailContent(), "text/html;charset=utf-8");// 支持html标签解析,展示自定义格式
// 组装邮件
MimeMultipart allFile = new MimeMultipart();
// 添加文本
allFile.addBodyPart(text);
// 添加附件
List<String> annexPaths = bean.getAnnexPaths();
if (annexPaths != null && annexPaths.size() > 0) {
for (String path : annexPaths) {
MimeBodyPart appendix = new MimeBodyPart();
DataHandler dataHandler = new DataHandler(new FileDataSource(path));
appendix.setDataHandler(dataHandler);
appendix.setFileName(new File(path).getName());
allFile.addBodyPart(appendix);//设置附件
}
}
allFile.setSubType("mixed"); //正文和附件都存在邮件中,所有类型设置为mixed
// 放到Message消息中
message.setContent(allFile);
// 显示的发件时间
message.setSentDate(new Date());
message.saveChanges();//保存修改
return message;
}
}
运行效果: