Java Web:邮件发送
邮件发送
一、介绍
1、传输协议
-
SMTP协议 (Simple Mail Transfer Protocol)
- 属于TCP/IP协议族。
- 控制信件的中转方式,帮助每台计算机在发送或中转信件时找到下一个目的地。
- SMTP服务器是遵循SMTP协议的发送邮件服务器。
-
POP3协议 (Post Office Protocol - Version 3)
- 属于TCP/IP协议族。
- 用于远程管理在服务器上的电子邮件,帮助用户登录到邮件服务器上、取邮件、删邮件等。
- POP服务器是遵循POP协议的邮件接收服务器。
2、邮件服务器
要在网络上实现邮件功能,要使用专门的邮件服务器。
- SMTP服务器 :一般是smtp.xxx.com。如163邮箱smtp.163.com,QQ邮箱smtp.qq.com。
- POP服务器:一般是pop.xxx.com。如163邮箱pop.163.com,QQ邮箱pop.qq.com。
3、原理图
- A通过SMTP协议连接到SMTP服务器,发送邮件到网易邮箱的SMTP服务器;
- 网易邮箱的SMTP服务器,通过SMTP协议将邮件中转到QQ邮箱的SMTP服务器;
- QQ邮箱的SMTP服务器,将接收到的邮件存储在B的邮箱账号
bbbb@qq.com
的邮箱空间中; - B通过POP3协议连接到POP服务器,请求收取邮件;
- POP服务器从B的邮箱账号的邮箱空间中取出邮件;
- POP服务器将取出来的邮件给B。
二、Java邮件发送
1、组件
- JavaMailAPI:
mail.jar
- Java Activation Framework:
activation.jar
2、实用类介绍
MailSSLSocketFactory类:设置SSL加密
// SSL加密:QQ邮箱需要设置,通过以下4行代码
MailSSLSocketFactory mssf = new MailSSLSocketFactory();
mssf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable", "true");
prop.put("mail.smtp.ssl.socketFactory", mssf);
Session类
// 获取实例对象
Session getDefaultInstance(Properties props)
Session getDefaultInstance(Properties props, Authenticator authenticator)
// 开启Debug模式
void setDebug(boolean debug)
// 获取Transport对象
Transport getTransport()
Transport类
// 连接到邮件服务器
void connect(String host, String user, String password)
// 发送邮件
void sendMessage(Message var1, Address[] var2)
// 关闭连接
void close()
MimePart接口实现类:MimeMessage类
// 设置发件人
void setFrom(Address address)
// 设置收件人
void setRecipient(Message.RecipientType type, Address address)
// 设置主题
void setSubject(String subject)
// 设置内容
void setContent(Object o, String type)
// 保存修改:添加图片、附件时需要
void saveChanges()
复杂邮件还需要以下2个类
MimePart接口实现类:MimeBodyPart类
复杂邮件的组成部分
// 文本:设置内容
void setContent(Object o, String type)
// 图片、附件:设置数据处理
void setDataHandler(DataHandler dh)
// 图片:设置CID,在文本中通过src引用
void setContentID(String cid)
// 附件:设置附件名
void setFileName(String filename)
MimePart接口实现类:MimeMultiPart类
组合多个代表MIME消息的MimeBodyPart对象。
// 添加MIME消息
void addBodyPart(BodyPart part)
// 描述数据关系:alternative/related/mixed
void setSubType(String subtype)
图示
3、实现步骤
普通邮件和复杂邮件的实现步骤相同,区别是邮件内容的不同
-
简单邮件:纯文本邮件,不含附件和图片;
-
复杂邮件:非纯文本邮件,包含附件和图片。
步骤
- 创建Session对象:
- 获取实例时,需要传入Properties参数;
- 用于定义邮件服务器所需的网络连接信息,如主机名、邮件协议、授权码等;
- 可以开启Debug模式,查看调试信息。
- 获得Transport对象:
- 通过Session获取;
- 连接到邮件服务器,需要传入端口号、发件人、授权码;
- 用于发送邮件。
- 创建邮件:
- MimeMessage,需要传入Session(拿到Session里的配置信息);
- 设置发件人、收件人、主题;
- 设置内容 (普通邮件和复杂邮件的区别)
- 发送Message,关闭连接:
- 发送时需要传入Message对象、收件人。
三、Java实现
以QQ邮箱为例
1、开启邮箱服务
得到授权码
2、代码实现
SendMail方法
要使用不同的邮箱服务器、邮箱账号等,只需修改参数即可
private void sendMail() throws MessagingException, GeneralSecurityException {
// 参数设置:根据不同的邮箱服务器和邮箱地址修改
final String host = "smtp.qq.com"; // 服务器主机号
final String authCode = "授权码"; // 授权码
final String addresser = "bbbb@qq.com"; // 发件人邮箱
final String addressee = "aaaa@126.com"; // 收件人邮箱
// 配置参数:可以写在配置文件中
Properties prop = new Properties();
prop.setProperty("mail.host", host);
prop.setProperty("mail.transport.protocol", "smtp");// 邮件协议
prop.setProperty("mail.smtp.auth", "true"); // 权限:验证用户名、授权码
// SSL加密:QQ邮箱需要设置,通过以下4行代码
MailSSLSocketFactory mssf = new MailSSLSocketFactory();
mssf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable", "true");
prop.put("mail.smtp.ssl.socketFactory", mssf);
// 1、创建Session对象
Session session = Session.getDefaultInstance(prop, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(addresser, authCode);
}
});
// 经测试,使用该构造方法也可以
// Session session = Session.getDefaultInstance(prop);
session.setDebug(true); // 开启Debug模式
// 2、获得Transport对象
Transport transport = session.getTransport();
transport.connect(host, addresser, authCode);
// 3、创建邮件:根据邮件类型调用相应方法(纯文本/内嵌资源/带附件)
MimeMessage message = makeSimpleMessage(session, addresser, addressee);
// 4、发送邮件
transport.sendMessage(message, message.getAllRecipients());
// 关闭邮件服务器
transport.close();
}
创建简单邮件
/**
* 创建简单邮件
*
* @param session Session对象
* @param addresser 发件人
* @param addressee 收件人
* @return 简单邮件
*/
private MimeMessage makeSimpleMessage(Session session, String addresser, String addressee) throws MessagingException {
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(addresser)); // 发件人
message.setRecipient(Message.RecipientType.TO, new InternetAddress(addressee)); // 收件人
message.setSubject("Java实现邮件发送:简单邮件"); // 邮件主题
// 邮件内容
message.setContent("<h1>MailSend的sendMail方法,发送一封普通邮件</h1>", "text/html;charset=utf-8");
return message;
}
创建复杂邮件
/**
* 创建复杂邮件
* 相比普通邮件增加:图片和附件(需要数据处理,设置CID和附件名)、描述数据关系、设置并保存修改
*
* @param session Session对象
* @param addresser 发件人
* @param addressee 收件人
* @return 复杂邮件
*/
private MimeMessage makeMixedMessage(Session session, String addresser, String addressee) throws MessagingException {
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(addresser)); // 发件人
message.setRecipient(Message.RecipientType.TO, new InternetAddress(addressee)); // 收件人
message.setSubject("Java实现邮件发送:复杂邮件"); // 邮件主题
// 邮件内容
// 1、正文
MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent("复杂邮件的正文,<img src='cid:Jay004'>附带一张图片", "text/html;charset=utf-8");
// 2、图片
MimeBodyPart imgPart = new MimeBodyPart();
DataHandler dh = new DataHandler(new FileDataSource("src\\main\\resources\\img\\Jay004.jpg"));
imgPart.setDataHandler(dh); // 需要数据处理
imgPart.setContentID("Jay004"); // 设置CID
// 3、附件
MimeBodyPart attachPart = new MimeBodyPart();
DataHandler dh1 = new DataHandler(new FileDataSource("src\\main\\resources\\md\\文件上传.md"));
attachPart.setDataHandler(dh1); // 需要数据处理
attachPart.setFileName("fileUpload.md"); // 设置附件名,最好包含后缀名
// 描述数据关系:alternative/related/mixed
MimeMultipart mm = new MimeMultipart();
mm.addBodyPart(textPart);
mm.addBodyPart(imgPart);
mm.addBodyPart(attachPart);
mm.setSubType("mixed");
// 设置到消息中,保存修改
message.setContent(mm);
message.saveChanges();
return message;
}
四、Java Web邮件发送
网站的注册功能中,经常会使用到邮件发送。
邮件的内容可能包含注册的用户名和密码、激活账户的超链接、激活码等信息。
五、Java Web实现
1、前端页面
register.jsp
<form action="register.do" method="post">
<label>
账号:<input type="text" name="username"><br>
</label>
<label>
密码:<input type="password" name="password"><br>
</label>
<label>
邮箱:<input type="text" name="mail"><br>
</label>
<input type="submit">|<input type="reset">
success.jsp
<h1>${msg}</h1>
2.1、Servlet
public class RegisterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String mail = req.getParameter("mail");
User user = new User(username, password, mail);
// 启动线程来发送邮件,优化注册等待时间
MailThread mailThread = new MailThread(user);
mailThread.start(); // start()才是开启多线程,run()只是调用方法
req.setAttribute("msg","注册成功,稍后会收到一封邮件");
req.getRequestDispatcher("success.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2.2、相关类
实体类:User
需要添加构造方法、Getter和Setter,如需在控制台调试可添加toString()方法。
public class User {
private String username; // 账户
private String password; // 密码
private String mailAddress; // 邮箱地址
}
工具类:MailThread
多线程实现邮件发送的意义:
- 如果不用多线程,在邮件成功发出后,程序才会继续运行;
- 用户体验差,等待时间长;
- 使用多线程优化,在完成注册后程序继续运行(如跳转页面等),邮件发送在单独的线程中完成。
public class MailThread extends Thread {
final private String host = "smtp.qq.com"; // 服务器主机号
final private String authCode = "yybjtadqjclodijh"; // 授权码
final private String addresser = "1666305862@qq.com"; // 发件人邮箱
final private User user;
public MailThread(User user) {
this.user = user;
}
@Override
public void run() {
try {
// 配置参数
Properties prop = new Properties();
prop.setProperty("mail.host", host);
prop.setProperty("mail.transport.protocol", "smtp");// 邮件协议
prop.setProperty("mail.smtp.auth", "true"); // 权限:验证用户名、授权码
// SSL加密:QQ邮箱需要设置,通过以下4行代码
MailSSLSocketFactory mssf = null;
mssf = new MailSSLSocketFactory();
mssf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable", "true");
prop.put("mail.smtp.ssl.socketFactory", mssf);
// 1、创建Session对象
Session session = Session.getDefaultInstance(prop, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(addresser, authCode);
}
});
session.setDebug(true); // 开启Debug模式
// 2、获得Transport对象
Transport transport = session.getTransport();
transport.connect(host, addresser, authCode);
// 3、创建邮件:调用相应方法(纯文本/内嵌资源/带附件)
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(addresser)); // 发件人
message.setRecipient(Message.RecipientType.TO, new InternetAddress(user.getMailAddress())); // 收件人
message.setSubject("用户注册邮件"); // 邮件主题
String info = "注册成功,您的用户名:" + user.getUsername() + ",密码:" + user.getPassword();
// 邮件内容
message.setContent(info, "text/html;charset=utf-8");
// 4、发送邮件
transport.sendMessage(message, new InternetAddress[]{new InternetAddress(user.getMailAddress())});
// 关闭邮件服务器
transport.close();
} catch (GeneralSecurityException | MessagingException e) {
e.printStackTrace();
}
}
}
3、注册Servlet
<servlet>
<servlet-name>RegisterServlet</servlet-name>
<servlet-class>indi.jaywee.mail.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RegisterServlet</servlet-name>
<url-pattern>/register.do</url-pattern>
</servlet-mapping>