邮件收发
在网络上实现邮件功能,必须要有专门的邮件服务器
这些邮件服务器类似于现实生活中的邮局,他主要负责接受用户投递过来的邮件,并把邮件投递到邮件接收者的电子邮箱中
SMTP服务器
地址:一般是 smtp.xxx.com
,比如163邮箱是smtp.163.com,QQ邮箱是smtp.qq.com
电子邮箱(E-mail地址)的获得需要在邮件服务器上进行申请。比如我们要使用QQ邮箱,就要开通邮箱功能
原理
传输协议
发送邮件:
- SMTP协议
- 我们通常把处理用户smtp请求(邮件发送请求)的服务器称之为SMTP服务器(邮件发送服务器)
接受邮件:
- POP3协议
- 我们通常把处理用户pop3请求(邮件接收请求)的服务器称之为POP3服务器(邮件接收服务器)
MIME:多用途互联网邮件扩展类型
- 说白了就是附件和图片
注意
有可能你收件人地址,发件人地址等信息都正确了,控制台也打印了正确的信息,但是在收件箱就是收不到信息。这是因为可能收件箱服务器拒收了你发的邮件(比如认为你的邮件是广告),这时候可能在垃圾箱里能找到,可能找不到。解决办法是重复的邮件内容不要多次发送,或者更换收件箱试试。
Maven依赖
<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.activation/activation -->
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
类的详解
代码示例
分为简单邮件和复杂邮件
简单邮件
:没有附件和图片,只有纯文本
复杂邮件
:带附件和图片的邮件
要发送邮件,要获得协议和支持!就是开启服务:POP3和SMTP服务
EasyMail.java
import com.sun.mail.util.MailSSLSocketFactory;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.security.GeneralSecurityException;
import java.util.Properties;
//发送一封简单的邮件
public class EasyMail {
public static void main(String[] args) throws GeneralSecurityException, MessagingException {
Properties prop = new Properties();
prop.setProperty("mail.host","smtp.qq.com"); //设置qq邮件服务器
prop.setProperty("mail.transport.protocol","smtp"); //邮件发送协议
prop.setProperty("mail.smtp.auth","true"); //需要验证用户密码
//关于QQ邮箱,还要设置SSL加密,加上以下代码即可,(阿里的钉钉邮箱也需要),其他邮箱看情况是否需要
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable","true");
prop.put("mail.smtp.ssl.socketFactory",sf);
//使用JavaMail发送邮件的五个步骤
//1,创建定义整个应用程序所需的环境信息的 Session 对象
//QQ才有!其他邮箱看情况用
Session session = Session.getDefaultInstance(prop, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("3070449936@qq.com","授权码");
}
});
//开启Session的debug模式,这样就可以看到程序发送的Email的运行状态
session.setDebug(true);
//2,通过 session 得到 Transport 对象
Transport ts = session.getTransport();
//3,使用邮箱的用户名和授权码连上邮件服务器
ts.connect("smtp.qq.com","3070449936@qq.com","授权码");
//4,创建邮件
//注意需要传递session
MimeMessage message = new MimeMessage(session);
//指明发件人
message.setFrom(new InternetAddress("3070449936@qq.com"));
//指明收件人,如果发件人和收件人一样,那就是自己给自己发
message.setRecipient(Message.RecipientType.TO, new InternetAddress("3070449936@qq.com"));
//设置邮件的主题
message.setSubject("easyTest");
//设置邮件的内容
//本质上是个html页面
message.setContent("<h1 style='color:red'>你好,easyMail</h1>","text/html;charset=UTF-8");
//5,发送邮件
ts.sendMessage(message, message.getAllRecipients());
//6,关闭连接
ts.close();
}
}
带图片和附件的邮件
带图片的邮件
import com.sun.mail.util.MailSSLSocketFactory;
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 java.security.GeneralSecurityException;
import java.util.Properties;
//带图片的邮件
public class ImageMail {
//和普通邮件相比,改动的只有创建邮件的步骤
public static void main(String[] args) throws GeneralSecurityException, MessagingException {
Properties prop = new Properties();
prop.setProperty("mail.host","smtp.qq.com"); //设置qq邮件服务器
prop.setProperty("mail.transport.protocol","smtp"); //邮件发送协议
prop.setProperty("mail.smtp.auth","true"); //需要验证用户密码
//关于QQ邮箱,还要设置SSL加密,加上以下代码即可,(阿里的钉钉邮箱也需要),其他邮箱看情况是否需要
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable","true");
prop.put("mail.smtp.ssl.socketFactory",sf);
//使用JavaMail发送邮件的五个步骤
//1,创建定义整个应用程序所需的环境信息的 Session 对象
//QQ才有!其他邮箱看情况用
Session session = Session.getDefaultInstance(prop, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("3070449936@qq.com","授权码");
}
});
//开启Session的debug模式,这样就可以看到程序发送的Email的运行状态
session.setDebug(true);
//2,通过 session 得到 Transport 对象
Transport ts = session.getTransport();
//3,使用邮箱的用户名和授权码连上邮件服务器
ts.connect("smtp.qq.com","3070449936@qq.com","授权码");
//4,创建邮件
//注意需要传递session
MimeMessage message = new MimeMessage(session);
//指明发件人
message.setFrom(new InternetAddress("3070449936@qq.com"));
//指明收件人,如果发件人和收件人一样,那就是自己给自己发
message.setRecipient(Message.RecipientType.TO, new InternetAddress("3070449936@qq.com"));
//设置邮件的主题
message.setSubject("easyTest");
//设置邮件的内容
//准备图片数据
MimeBodyPart image = new MimeBodyPart();
//图片经过数据处理
DataHandler dh = new DataHandler(new FileDataSource("src/resources/xxx.jpg"));
image.setDataHandler(dh); //在我们的Body主体中放入这个处理的图片数据
image.setContentID("xxx.jpg"); //给图片设置一个ID,我们在后面可以使用
//准备正文数据
MimeBodyPart text = new MimeBodyPart();
//下面的cid就是上面setContentID的缩写,这里可以引用到那张图片
text.setContent("这是一封正文带图片<img src='cid:xxx.jpg'>的邮件","text/html;charset=UTF-8");
//描述数据关系
MimeMultipart mm = new MimeMultipart();
mm.addBodyPart(text);
mm.addBodyPart(image);
mm.setSubType("related"); //按照图里面的层级来,如果有附件,则是mixed
//设置到消息中,保存修改
message.setContent(mm);
message.saveChanges();
//5,发送邮件
ts.sendMessage(message, message.getAllRecipients());
//6,关闭连接
ts.close();
}
}
带图片和附件的邮件
import com.sun.mail.util.MailSSLSocketFactory;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import java.security.GeneralSecurityException;
import java.util.Properties;
//带附件和图片的邮件
public class DiffcultMail {
public static void main(String[] args) throws GeneralSecurityException, MessagingException {
Properties prop = new Properties();
prop.setProperty("mail.host","smtp.qq.com"); //设置qq邮件服务器
prop.setProperty("mail.transport.protocol","smtp"); //邮件发送协议
prop.setProperty("mail.smtp.auth","true"); //需要验证用户密码
//关于QQ邮箱,还要设置SSL加密,加上以下代码即可,(阿里的钉钉邮箱也需要),其他邮箱看情况是否需要
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable","true");
prop.put("mail.smtp.ssl.socketFactory",sf);
//1,创建定义整个应用程序所需的环境信息的 Session 对象
//QQ才有!其他邮箱看情况用
Session session = Session.getDefaultInstance(prop, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("3070449936@qq.com","授权码");
}
});
//开启Session的debug模式,这样就可以看到程序发送的Email的运行状态
session.setDebug(true);
//2,通过 session 得到 Transport 对象
Transport ts = session.getTransport();
//3,使用邮箱的用户名和授权码连上邮件服务器
ts.connect("smtp.qq.com","3070449936@qq.com","授权码");
//4,创建邮件
//注意需要传递session
MimeMessage mimeMessage = setDiffcultMail(session);
//5,发送邮件
ts.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
//6,关闭连接
ts.close();
}
public static MimeMessage setDiffcultMail(Session session) throws MessagingException {
//消息的固定信息
MimeMessage mimeMessage = new MimeMessage(session);
//邮件发送人
mimeMessage.setFrom(new InternetAddress("3070449936@qq.com"));
//邮件接收人
mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress("3070449936@qq.com"));
//设置主题
mimeMessage.setSubject("你猜这是啥邮件!");
//图片
MimeBodyPart body1 = new MimeBodyPart();
body1.setDataHandler(new DataHandler(new FileDataSource("src/xxx.png")));
body1.setContentID("xxx.jpg");
//文本
MimeBodyPart body2 = new MimeBodyPart();
body2.setContent("请注意,我不是广告<img src='cid:xxx.png'>","text/html;charset=UTF-8");
//附件
MimeBodyPart body3 = new MimeBodyPart();
body3.setDataHandler(new DataHandler(new FileDataSource("src/xxx.xml")));
body3.setFileName("xxx.xml"); //设置附件名字
MimeBodyPart body4 = new MimeBodyPart();
body4.setDataHandler(new DataHandler(new FileDataSource("src/xxx.txt")));
body4.setFileName("xxx.txt");
//拼装邮件内容
MimeMultipart mimeMultipart = new MimeMultipart();
mimeMultipart.addBodyPart(body1);
mimeMultipart.addBodyPart(body2);
mimeMultipart.addBodyPart(body3);
mimeMultipart.addBodyPart(body4);
mimeMultipart.setSubType("mixed"); //文本,图片和附件都在邮件中,所以类型设置为mixed
//放到Message消息中
mimeMessage.setContent(mimeMultipart);
mimeMessage.saveChanges();
return mimeMessage;
}
}
项目实例
pojo/User.java
import java.io.Serializable;
//Serializable接口是为了远程调用时需要序列化,否则外部调用实体类时会报错
//Serializable是标记接口,虚拟机在识别到实现了这个接口的类时会做一些操作
public class User implements Serializable {
private String username;
private String password;
private String email;
public User() {
}
public User(String username, String password, String email) {
this.username = username;
this.password = password;
this.email = email;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
'}';
}
}
util/SendMail.java
import com.mahe666.pojo.User;
import com.sun.mail.util.MailSSLSocketFactory;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.security.GeneralSecurityException;
import java.util.Properties;
//网站三秒原则:用户体验
//通过多线程发邮件,然后用户可以在做别的事情的时候,完成发邮件的业务 (异步处理)
//这就是为什么很多公司都要问关于多线程的面试题
public class SendMail extends Thread {
//用户给用户发邮件的邮箱
private String from = "m13234666930@163.com";
//邮箱的用户名
private String username = "m13234666930@163.com";
//邮箱的授权码
private String password = "授权码";
//发送邮件的服务地址
private String host = "smtp.163.com";
private User user;
public SendMail(User user) {
this.user = user;
System.out.println(user);
}
@Override
public void run() {
try{
Properties prop = new Properties();
prop.setProperty("mail.host", host); //设置qq邮件服务器
prop.setProperty("mail.transport.protocol", "smtp"); //邮件发送协议
prop.setProperty("mail.smtp.auth", "true"); //需要验证用户密码
MailSSLSocketFactory sf = null;
try {
sf = new MailSSLSocketFactory();
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable", "true");
prop.put("mail.smtp.ssl.socketFactory", sf);
Session session = Session.getDefaultInstance(prop, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username,password);
}
});
session.setDebug(true);
Transport ts = session.getTransport();
ts.connect(host,username,password);
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.setRecipient(Message.RecipientType.TO, new InternetAddress(user.getEmail()));
message.setSubject("验证邮件");
//设置邮件的内容
String info = "恭喜您注册成功!您的用户名为:"+user.getUsername()+" ,您的密码为:"+user.getPassword()+" 请妥善保管";
message.setContent(info,"text/html;charset=UTF-8");
message.saveChanges();
//5,发送邮件
ts.sendMessage(message, message.getAllRecipients());
ts.close();
}catch (MessagingException e){
e.printStackTrace();
}
}
}
servlet/RegisterServlet.java
import com.mahe666.pojo.User;
import com.mahe666.util.SendMail;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class RegisterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
User user = new User(username, password, email);
//我们注册成功后,给用户发送一封邮件
//我们使用线程来专门发送邮件,防止出现耗时,和网站注册人数过多的情况
SendMail sendMail = new SendMail(user);
sendMail.start();
//注册用户
String info = "注册成功,我们已经发送了一封电子邮件到您的邮箱,请查收,如果网络不稳定,可能过一会儿才能收到";
req.setAttribute("message",info);
req.getRequestDispatcher("/info.jsp").forward(req,resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
<servlet>
<servlet-name>RegisterServlet</servlet-name>
<servlet-class>com.mahe666.servlet.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RegisterServlet</servlet-name>
<url-pattern>/register.do</url-pattern>
</servlet-mapping>
</web-app>
register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>注册</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/register.do" method="post">
username:<input type="text" name="username"><br/>
password:<input type="password" name="password"><br/>
e-mail:<input type="text" name="email"><br/>
<input type="submit" value="注册">
</form>
</body>
</html>
info.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>信息</title>
</head>
<body>
${message}
</body>
</html>