邮件收发
转自这位大佬
电子邮件
要在网络上实现邮件功能,必须要有专门的邮件服务器。
这些邮件服务器类似于现实生活中的邮局,它主要负责接收用户投递过来的邮件,并把邮件投递到邮件接收者的电子邮箱中。
SMTP服务器地址:一般是smtp.xxx.com,比如163邮箱是smtp.163.com,qq邮箱是smtp.qq.com,
电子邮箱(E-Mail地址)的获得需要在邮件服务器上进行申请。比如我们要使用QQ邮箱就需要开通邮箱功能;
传输协议
SMTP协议
发送邮件:
我们通常把处理用户smtp请求(邮件发送请求)的服务器称之为SMTP服务器(邮件发送服务器)。
POP3协议
接收邮件:
我们通常把处理用户pop3请求(邮件接收请求)的服务器称之为POP3服务器(邮件接收服务器)。
邮件收发原理
1.大狂神通过smtp协议连接到smtp服务器,然后发送一封邮件给网易的邮件服务器
2.网易分析发现需要去QQ的邮件服务器,通过smtp协议将邮件转投给QQ的Smtp服务器
3.QQ将接收到的邮件存储在24736743@qq.com这个邮件账号的空间中
4.小狂神通过Pop3协议连接到Pop3服务器收取邮件
5.从24736743@qq.com这个邮件账号的空间中取出邮件
6.Pop3服务器将取出来的邮件送到小狂神手中
【注意】有可能你收件人地址,发件人地址等信息都正确了,控制台也打印了正确的信息,但是在收件箱就是收不到信息。这是因为可能收件箱服务器拒收了你发的邮件(比如认为你的邮件是广告),这时候可能在垃圾箱里能找到,可能找不到。解决办法是重复的邮件内容不要多次发送,或者更换收件箱试试
java发邮件
概述
我们将用代码完成邮件的发送。这在实际项目中应用的非常广泛,比如注册需要发送邮件进行账号激活,再比如oA项目中利用邮件进行任务提醒等等。
使用Java发送E-mail十分简单,但是首先你应该准备 JavaMail ApI 和 Java Activation Framework。
得到两个jar包:
mail.jar activation.jar
JavaMail是sun公司(现以被甲骨文收购)为方便Java开发人员在应用程序中实现邮件发送和接收功能而提供的一套标准开发包,它支持一些常用的邮件协议,如前面所讲的SMTP,POP3,IMAP,还有MIME等。我们在使用JavaMail API编写邮件时,无须考虑邮件的底层实现细节,只要调用JavaMail开发包中相应的API类就可以了。
<!-- 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>
我们可以先尝试发送一封简单的邮件,确保电脑可以连接网络。
。创建包含邮件服务器的网络连接信息的session对象。
。创建代表邮件内容的Message对象
。创建Transport对象,连接服务器,发送Message,关闭连接
主要有四个核心类,我们在编写程序时,记住这四个核心类,就很容易编写出Java邮件处理程序。
现在项目中导入jar包
<!-- 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>
具体实现
package com.Wang.servlet;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 MailDemo01 {public static void main(String[] args) throws Exception {Properties prop = new Properties();prop.setProperty( "mail.host", "smtp.qq.com"); //设置og邮件服务器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发送邮件的s个步骤//1、创建定义整个应用程序所需的环境信息的session 对象//QQ才有! 其他邮箱就不用Session session = Session.getDefaultInstance(prop,new Authenticator() {public PasswordAuthentication getPasswordAuthentication() {//发件人邮件用户名、授权码return new PasswordAuthentication( "2076312724@qq.com", "idwsficexslzdjia");}});//开启Session的debug模式,这样就可以查看到程序发送Email的运行状态session.setDebug(true) ;//2、通过session得到transport对象Transport ts = session.getTransport();//3、使用邮箱的用户名和授权码连上邮件服务器ts.connect("smtp.qq.com","2076312724@qq.com","idwsficexslzdjia");//4、创建邮件//创建邮件对象MimeMessage message = new MimeMessage(session);//指明邮件的发件人message.setFrom( new InternetAddress("2076312724@qq.com" ) );//指明邮件的收件人,现在发件人和收件人是一样的,那就是自己给自己发message.setRecipient(Message.RecipientType.TO,new InternetAddress("2076312724@qq.com"));//邮件的标题message.setSubject("只包含文本的简单邮件");//邮件的文本内容message.setContent("你好啊! ", "text/html;charset=UTF-8" );//5、发送邮件ts.sendMessage(message,message.getAllRecipients());//6.关闭连接ts.close();}
}
复杂邮件就是非纯文本的邮件,可能还包含了图片和附件等资源
先认识两个类一个名词:
MIME(多用途互联网邮件扩展类型)
- MimeBodyPart类
javax.mail.internet.MimeBodyPart类表示的是一个MIME消息,它和MimeMessage类一样都是从Part接口继承过来。即一个MIME消息对应一个MimeBodyPart对象,而MimeBodyPart对象就是我们写的邮件内容中的元素
- MimeMultipart类
javax.mail.internet.MimeMultipart是抽象类 Multipart的实现子类,它用来组合多个MIME消息。一个MimeMultipart对象可以包含多个代表MIME消息的MimeBodyPart对象。即一个MimeMultipart对象表示多个MimeBodyPart的集合,而一个MimeMultipart表示的就是我们一封邮件的内容
MimeMultipart对象的使用的时候需要设置setSubType()的属性值,一共就下面3种取值
alternative:表明这个MimeMultipart对象中的MimeMessage对象的数据是纯文本文件
related:表明这个MimeMultipart对象中的MimeMessage对象的数据包含非纯文本文件
mixed:表明这个MimeMultipart对象中的MimeMessage对象的数据包含附件
我们在使得的时候如果不知道使用哪一个,直接使用mixed即可,使用这个属性值一定不会报错
相较于简单邮件,复杂邮件变化的地方只是在于邮件内容本身会发送变化,而其他的步骤都是一样的
1、准备一些参数
2、获取session对象
3、获取传输对象
4、登陆授权
5、写邮件 (和简单邮件相区别)
6、发送邮件
7、关闭服务器资源
1、发送包含图片的复杂邮件
package com.thhh;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.util.Properties;//发送一封简单的邮件
public class MailDemo01 {public static void main(String[] args) throws Exception {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发送邮件的5个步骤//1、创建定义整个应用程序所需的环境信息的 Session 对象//使用QQ邮箱的时候才需要,其他邮箱不需要这一段代码Session session = Session.getDefaultInstance(prop, new Authenticator() {//获取和SMTP服务器的连接对象public PasswordAuthentication getPasswordAuthentication() {//发件人邮件用户名、授权码return new PasswordAuthentication("XXXX@qq.com", "授权码");}});//开启Session的debug模式,这样就可以查看到程序发送Email的运行状态session.setDebug(true);//2、通过session得到transport对象Transport ts = session.getTransport();//通过这一次和SMTP服务器的连接对象获取发送邮件的传输对象//3、使用邮箱的用户名和授权码连上SMTP邮件服务器,即登陆ts.connect("smtp.qq.com", "XXXX@qq.com", "授权码");//4、创建邮件对象MimeMessage——点击网页上的写信//创建一个邮件对象MimeMessage message = new MimeMessage(session);//指明邮件的发件人——在网页上填写发件人message.setFrom(new InternetAddress("XXXX@qq.com"));//设置发件人//指明邮件的收件人,现在发件人和收件人是一样的,那就是自己给自己发——在网页上填写收件人message.setRecipient(Message.RecipientType.TO, new InternetAddress("XXXX@qq.com"));//设置收件人//邮件的标题——在网页上填写邮件标题message.setSubject("简单邮件发送实现");//设置邮件主题System.out.println("=============================复杂邮件的邮件内容设置==================================");// 准备邮件数据// 准备图片数据MimeBodyPart image = new MimeBodyPart();//获取一个图片的MimeBodyPart对象DataHandler dh = new DataHandler(new FileDataSource("图片的绝对地址"));//由于图片需要字符化才能传输,所以需要获取一个DataHandler对象image.setDataHandler(dh);//将图片序列化image.setContentID("bz.jpg");//为图片的MimeBodyPart对象设置一个ID,我们在文字中就可以使用它了// 准备正文数据MimeBodyPart text = new MimeBodyPart();//获取一个文本的MimeBodyPart对象text.setContent("这是一封邮件正文带图片<img src='cid:bz.jpg'>的邮件", "text/html;charset=UTF-8");//设置文本内容,注意在里面嵌入了<img src='cid:bz.jpg'>// 描述数据关系MimeMultipart mm = new MimeMultipart();//获取MimeMultipartmm.addBodyPart(text);//将文本MimeBodyPart对象加入MimeMultipart中mm.addBodyPart(image);//将图片MimeBodyPart对象加入MimeMultipart中mm.setSubType("related");//设置MimeMultipart对象的相对熟悉为related,即发送的数据为文本+非附件资源//设置到消息中,保存修改message.setContent(mm);//将MimeMultipart放入消息对象中message.saveChanges();//保存上面的修改System.out.println("===============================================================");//5、发送邮件——在网页上点击发送按钮ts.sendMessage(message, message.getAllRecipients());//6、关闭连接对象,即关闭服务器上的连接资源ts.close();}
}
只改了第5步
// 准备邮件数据// 准备图片数据 MimeBodyPart image = new MimeBodyPart();//获取一个图片的MimeBodyPart对象DataHandler dh = new DataHandler(new FileDataSource("图片的绝对地址"));//由于图片需要字符化才能传输,所以需要获取一个DataHandler对象image.setDataHandler(dh);//将图片序列化image.setContentID("bz.jpg");//为图片的MimeBodyPart对象设置一个ID,我们在文字中就可以使用它了// 准备正文数据MimeBodyPart text = new MimeBodyPart();//获取一个文本的MimeBodyPart对象text.setContent("这是一封邮件正文带图片<img src='cid:bz.jpg'>的邮件", "text/html;charset=UTF-8");//设置文本内容,注意在里面嵌入了<img src='cid:bz.jpg'>// 描述数据关系MimeMultipart mm = new MimeMultipart();//获取MimeMultipartmm.addBodyPart(text);//将文本MimeBodyPart对象加入MimeMultipart中mm.addBodyPart(image);//将图片MimeBodyPart对象加入MimeMultipart中mm.setSubType("related");//设置MimeMultipart对象的相对熟悉为related,即发送的数据为文本+非附件资源//设置到消息中,保存修改message.setContent(mm);//将MimeMultipart放入消息对象中message.saveChanges();//保存上面的修改
2、发送包含附件的复杂邮件
System.out.println("=============================复杂邮件的邮件内容设置==================================");/*
编写邮件内容
1.图片
2.附件
3.文本*///图片
MimeBodyPart body1 = new MimeBodyPart();
body1.setDataHandler(new DataHandler(new FileDataSource("图片的绝对地址")));
body1.setContentID("yhbxb.png"); //图片设置ID//文本
MimeBodyPart body2 = new MimeBodyPart();
body2.setContent("请注意,我不是广告<img src='cid:yhbxb.png'>","text/html;charset=utf-8");//附件
MimeBodyPart body3 = new MimeBodyPart();
body3.setDataHandler(new DataHandler(new FileDataSource("附件1的绝对地址")));
body3.setFileName("test.c"); //附件设置名字MimeBodyPart body4 = new MimeBodyPart();
body4.setDataHandler(new DataHandler(new FileDataSource("附件2的绝对地址")));
body4.setFileName("test.txt"); //附件设置名字//拼装邮件正文内容
MimeMultipart multipart1 = new MimeMultipart();
multipart1.addBodyPart(body1);
multipart1.addBodyPart(body2);
multipart1.setSubType("related"); //1.文本和图片内嵌成功!//new MimeBodyPart().setContent(multipart1); //将拼装好的正文内容设置为主体
MimeBodyPart contentText = new MimeBodyPart();
contentText.setContent(multipart1);//拼接附件
MimeMultipart allFile =new MimeMultipart();
allFile.addBodyPart(body3); //附件
allFile.addBodyPart(body4); //附件
allFile.addBodyPart(contentText);//正文
allFile.setSubType("mixed"); //正文和附件都存在邮件中,所有类型设置为mixed;//设置到消息中,保存修改
message.setContent(allFile);//将MimeMultipart放入消息对象中
message.saveChanges();//保存上面的修改System.out.println("===============================================================");
功能测试通过!
网站注册发送邮件功能实现
分析:在我们注册的时候,前端我们填写的就是一个表单,这个表单提交给后端的servlet,这个servlet就向我们填写的那个邮箱中发送一封邮件
1.所以我们需要创建一个javaweb项目,因为要使用到前端页面+servlet
拷贝两个前端素材
注册页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--注册填写邮箱的前端页面--%>
<html>
<head><title>注册</title>
</head>
<body><form action="${pageContext.request.contextPath}/RegisterServlet.do" method="post">用户名:<input type="text" name="username"><br/>密码:<input type="password" name="password"><br/>邮箱:<input type="text" name="email"><br/><input type="submit" value="注册">
</form></body>
</html>
提示成功页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>提示信息</title>
</head>
<body>
<h2>thhh提醒您</h2>${message}
</body>
</html>
编写servlet
package com.thhh.servlet;import com.thhh.pojo.User;
import com.thhh.utils.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 {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//1、接收用户填写的表单数据String username = req.getParameter("username");String password = req.getParameter("password");String email = req.getParameter("email");
// System.out.println(username+password+email);//2、向用户邮箱发送邮件,注意发送邮件很耗时,所以我们启动一个子线程去做这件事,而用户则是直接跳转注册成功页面,以免降低用户体验User user = new User(username,password,email);Sendmail sendmail = new Sendmail(user);//获取子线程对象new Thread(sendmail).start();//启动子线程//3、视图跳转req.setAttribute("message","注册成功!我们已经向您的邮箱发送了邮件,请您及时进行查收。由于网络原因,您收到邮件的时间存在延迟,敬请谅解~");req.getRequestDispatcher("info.jsp").forward(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}
多线程工具类
package com.thhh.utils;//多线程实现邮件发送
//使用多线程的原因就是提高用户的体验,一旦一个页面3s及以上的时间白屏就可能被用户关掉
//所以我们在用户提交表单之后,将费时的邮件发送工作使用一个子线程来完成,而主线程还是去完成它自己的事情
//这么做就可以提高用户体验,不然用户等待邮件发送的时间import com.sun.mail.util.MailSSLSocketFactory;
import com.thhh.pojo.User;import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.security.GeneralSecurityException;
import java.util.Properties;//多线程这种处理就可以称为异步处理
public class Sendmail implements Runnable{private String from = "XXXX@qq.com";//我们用来向客户发送邮件的邮箱private String username = "XXXX@qq.com";//用于登陆SMTP服务器的用户名private String password = "授权码";//授权码
private User user;
public Sendmail(User user) {this.user = user;//用于获取用户邮箱地址
}@Override
public void run() {try {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发送邮件的5个步骤//1、创建定义整个应用程序所需的环境信息的 Session 对象//使用QQ邮箱的时候才需要,其他邮箱不需要这一段代码Session session = Session.getDefaultInstance(prop, new Authenticator() {//获取和SMTP服务器的连接对象public PasswordAuthentication getPasswordAuthentication() {//发件人邮件用户名、授权码return new PasswordAuthentication(username, password);}});//开启Session的debug模式,这样就可以查看到程序发送Email的运行状态session.setDebug(true);//2、通过session得到transport对象Transport ts = session.getTransport();//通过这一次和SMTP服务器的连接对象获取发送邮件的传输对象//3、使用邮箱的用户名和授权码连上SMTP邮件服务器,即登陆ts.connect("smtp.qq.com", username, password);//4、创建邮件对象MimeMessage——点击网页上的写信//创建一个邮件对象MimeMessage message = new MimeMessage(session);//指明邮件的发件人——在网页上填写发件人message.setFrom(new InternetAddress(username));//设置发件人//指明邮件的收件人,现在发件人和收件人是一样的,那就是自己给自己发——在网页上填写收件人message.setRecipient(Message.RecipientType.TO, new InternetAddress(user.getEmail()));//设置收件人//邮件的标题——在网页上填写邮件标题message.setSubject("欢迎注册thhh!");//设置邮件主题//邮件的文本内容——在网页上填写邮件内容message.setContent("<p><h2>恭喜注册成功!</h2></p>您的用户名为:<h4>"+user.getUsername()+"</h4>请妥善保管您的密码,如有问题请及时联系网站客服,再次欢迎您的加入!!", "text/html;charset=UTF-8");//设置邮件的具体内容//5、发送邮件——在网页上点击发送按钮ts.sendMessage(message, message.getAllRecipients());//6、关闭连接对象,即关闭服务器上的连接资源ts.close();} catch (MessagingException e) {e.printStackTrace();} catch (GeneralSecurityException e) {e.printStackTrace();}
}
}
测试
测试成功了!
感悟
整个邮件发送的实现我们都是依赖的两个jar包:mail.jar、activation.jar
这两个jar包导入之后我们就在按照固定的调用这两个jar包中的功能进行代码编写,其实代码+步骤都是写死的,我们只需要复制粘贴,然后修改一下参数就可以在我们自己的项目上跑起来了,所以对于这个例子,我们只需要掌握使用Java发送邮件的原理/需要哪些步骤,而不用去记住代码怎么实现的,如果真的到了要用的时候,我们可以直接在网上搜索一下,这种例子一大堆,所以重点还是要学习实现原理,在理解原理的基础上那这个项目锻炼一下自己的编码+排错能力+提升对IDE的熟悉度
通过这个例子我们也更进一步的理解了为什么说在Java中万物皆对象:我们对邮件的操作中,获取客户端与SMTP服务器的连接需要一个session对象、进行客户端和SMTP服务器之间的数据传输需要使用Transport 对象、发送纯文本邮件需要使用MimeMessage 对象、发送非纯文本邮件需要使用MimeMultipart对象…
收获
1.在这个项目中我们还可以加深对一个javaweb项目文件结构的熟悉
2.加深我们在IDEA中创建WEB项目的3种方法:直接创建javaweb项目、创建一个干净的maven项目再添加web文件夹和直接使用maven创建一个javaweb项目
3.实践了"小黄鸭调试法"
4.见识了使用注解+框架开发的简便
5.实现了期待的功能
测试成功了!
感悟
整个邮件发送的实现我们都是依赖的两个jar包:mail.jar、activation.jar
这两个jar包导入之后我们就在按照固定的调用这两个jar包中的功能进行代码编写,其实代码+步骤都是写死的,我们只需要复制粘贴,然后修改一下参数就可以在我们自己的项目上跑起来了,所以对于这个例子,我们只需要掌握使用Java发送邮件的原理/需要哪些步骤,而不用去记住代码怎么实现的,如果真的到了要用的时候,我们可以直接在网上搜索一下,这种例子一大堆,所以重点还是要学习实现原理,在理解原理的基础上那这个项目锻炼一下自己的编码+排错能力+提升对IDE的熟悉度
通过这个例子我们也更进一步的理解了为什么说在Java中万物皆对象:我们对邮件的操作中,获取客户端与SMTP服务器的连接需要一个session对象、进行客户端和SMTP服务器之间的数据传输需要使用Transport 对象、发送纯文本邮件需要使用MimeMessage 对象、发送非纯文本邮件需要使用MimeMultipart对象…
收获
1.在这个项目中我们还可以加深对一个javaweb项目文件结构的熟悉
2.加深我们在IDEA中创建WEB项目的3种方法:直接创建javaweb项目、创建一个干净的maven项目再添加web文件夹和直接使用maven创建一个javaweb项目
3.实践了"小黄鸭调试法"
4.见识了使用注解+框架开发的简便
5.实现了期待的功能