WEB后台邮件和短信业务实现包括Java一键实现封装和异步以及原理详解.docx
《WEB后台邮件和短信业务实现包括Java一键实现封装和异步以及原理详解.docx》由会员分享,可在线阅读,更多相关《WEB后台邮件和短信业务实现包括Java一键实现封装和异步以及原理详解.docx(29页珍藏版)》请在冰点文库上搜索。
WEB后台邮件和短信业务实现包括Java一键实现封装和异步以及原理详解
WEB后台--邮件和短信业务实现(包括Java一键实现、封装和异步)以及原理详解
本来就打算针对一些固定的特别点的业务(QQ与网易邮件、拦截设计、短信、定时器等等)来进行记录以及解析原理,这些会比较零散记录在JavaWeb的分类里面,感兴趣的童鞋可以去看下。
有人问为什么要邮件短信一起写,呃,短信的东西,非巨型公司都是用第三方的,第三方的文档支持都十分完整,短信例子的话,我一会也是引用第三方去做一个而已。
主要在于原理,两个都是十分相近的业务,而且都是在TCP/IP的应用层封装,并且设计的重传方案基本相似。
重传方案,为了避免本篇过长,我会在后面一篇文章写出,结合线程或者定时器的重传方案。
文章结构:
(1)邮件实现与原理;
(2)短信实现与原理。
DEMO在本文最下方。
文章目录:
(1)邮件实现与原理
邮件概述(邮件在互联网通信架构中的位置)
一个邮件系统的组成分析
邮件系统–邮件通信过程如图
邮件协议详解
Java一键实现邮件发送
Java邮件封装和异步实现
(2)短信实现与原理
短信的概述:
(短信在互联网通信架构中的位置)
短信原理
短信系统–短信通信过程
短信的协议
一键实现短信发送
Java短信封装和异步实现
一、邮件实现与原理:
(1)邮件概述(邮件在互联网通信架构中的位置):
上图就是互联网的TCP/IP架构。
具体详情请见我的【计算机网络系列】。
应用层定义了应用程序使用互联网的规程。
电子邮件的协议就建立在这一层。
/*
*为什么建立在TCP/IP的应用层?
?
原因是?
?
*
*首先确立在现今社会,企业的正式工作都是通过邮件进行。
邮件对于可靠性要求非常高,所以就要求一个可靠的传输协议。
就把邮件协议建立在TCP/IP的应用层基础上了。
IP协议的主要功能包括无连结数据报传送﹑数据报寻径以及差错处理三部分。
IP协议的特点是点到点的,IP对等实体间的通信不经过中间机器,对等实体所在的机器位于同一物理网络,对等机器之间有直接的物理连接。
IP层的主要功能是屏蔽下面物理层的差别,向上一层提供一致的数据格式。
所有要传输的数据,被按照一定的格式分组封装层IP数据报,数据报单元通过寻径等机制进行传输,在接收方数据报进行重组,得到最初要传送的数据。
由于IP协议是不可靠的数据传输协议,由于网络的拥塞而发生的数据丢失等情况是不可避免的,因此Internet还必须有一定的控制重传机制,这就是差错与控制报文协议(ICMP)。
但IP协议还不能解决数据分组在传输过程中可能出现的问题。
(透明传输等问题)。
因此,还需要TCP协议来提供可靠的并且无差错的通信服务。
TCP协议被称作一种端对端协议。
这是因为它为两台计算机之间的连接起了重要作用:
当一台计算机需要与另一台远程计算机连接时,TCP协议会让它们建立一个连接、发送和接收数据以及终止连接。
传输控制协议TCP协议利用重发技术和拥塞控制机制,向应用程序提供可靠的通信连接,使它能够自动适应网上的各种变化。
IP协议只保证计算机能发送和接收分组数据,而TCP协议则可提供一个可靠的、可流控的、全双工的信息流传输服务。
虽然IP和TCP这两个协议的功能不尽相同,也可以分开单独使用,但它们是在同一时期作为一个协议来设计的,并且在功能上也是互补的。
只有两者的结合,才能保证Internet在复杂的环境下正常运行。
凡是要连接到Internet的计算机,都必须同时安装和使用这两个协议,因此在实际中常把这两个协议统称作TCP/IP协议。
TCP/IP协议除了TCP协议和IP协议,还包含物理接口和IP层之间的ARP/RARP协议,应用层的FTP协议﹑SMTP协议和BOOTP协议等,所用的这些协议构成Intenet的TCP/IP协议族。
*/
(2)一个邮件系统的组成分析:
一个邮件系统组成必须包括邮件服务器,然后是用户代理和邮件传送协议。
(一)邮件服务器。
(存储用户邮箱的地方)
是一个供在网上存储邮件的空间。
一般每个邮件服务器的提供商都有自己的邮件服务器,只要你申请了他的邮箱账号,你就会在他的邮件服务器上拥有自己邮箱。
像Google,腾讯都是邮件服务的提供商,他们都有自己的邮件服务器,如果你申请了Gamil邮箱,那么在Google的邮件服务器上面,你就有自己的一块存储空间了。
同样,如果你申请了qq邮箱,那么在qq邮件服务器上面也有你自己的空间了,也就是你的邮箱。
当你要收取信件的时候,你就需要连接到不同的服务器上面。
不同的邮件服务提供商,他们的邮件服务器的地址是不一样的。
后面会介绍一些常用的邮件服务器的地址。
(二)用户代理:
(用户读取邮件的地方)
就是你用来从邮件服务器上读取或者发送邮件到邮件服务器上的一个软件。
比如常用的OutLook,qq邮箱(公司呈现出来的,邮箱服务器是看不到的另一区域)等等。
我们知道,我们的邮件都是存储在邮件服务器上面的,我们发送邮件的时候,去往邮件服务器上面发,我们收取邮件的时候,也需要从服务器上面读。
为了方便的完成这些工作,我们就需要用户代理。
(三)邮件传送协议:
(邮箱信息发送的约定)
是指邮件在传送过程中必须遵守的约定,它规定了不同的服务器(或客户端)之间应如何交换信息。
比较常见的有邮件服务器之间的通信协议SMTP以及用户代理与邮件服务器之间的通信协议POP3。
(注意:
邮件服务器之间的协议是使用SMTP,用户发送邮件到邮件服务器使用的还是SMTP协议,用户从邮件服务器读取邮件用的才是POP3协议)。
(3)邮件系统–邮件通信过程如图:
邮件通信过程(文字描述):
1)发信人调用自己的用户代理撰写、编辑邮件,并写清楚收件人的邮箱地址;
2)发信人的用户代理根据发信人编辑的信息,生成一封符合邮件格式的邮件;
3)发信人的用户代理把邮件发送到发信人的的邮件服务器上,邮件服务器上面有一个缓冲队列,发送到邮件服务器上面的邮件都会加入到缓冲队列中,等待邮件服务器上的SMTP客户端进行发送;
4)发信人的邮件服务器的SMTP客户端与接收方邮件服务器的SMTP服务器建立TCP连接,发信人的邮件服务器使用SMTP协议把这封邮件发送到收件人的邮件服务器上(它会自动根据收件人的邮箱来分析出收件人的邮箱服务器);
5)收件人的邮件服务器收到邮件后,把这封邮件放到收件人在这个服务器上的邮箱中,等待收件人进行读取;
6)收件人使用他的用户代理来收取邮件。
首先用户代理使用POP3协议来连接收件人所在的邮件服务器,身份验证成功后,用户代理就可以把邮件服务器上面的收件人邮箱里面的邮件读取出来,并展示给收件人。
(4)邮件协议详解:
(一)SMTP:
SMTP(SimpleMailTransferProtocol)即简单邮件传输协议,是一种提供可靠且有效电子邮件传输的协议。
SMTP是建立在FTP文件传输服务上的一种邮件服务,主要用于传输系统之间的邮件信息并提供与来信有关的通知。
SMTP主要负责底层的邮件系统如何将邮件从一台机器传至另外一台机器。
SMTP提供了一种邮件传输的机制,当收件方和发件方都在一个网络上时,可以把邮件直传给对方;当双方不在同一个网络上时,需要通过一个或几个中间服务器转发。
SMTP首先由发件方提出申请,要求与接收方SMTP建立双向的通信渠道,收件方可以是最终收件人也可以是中间转发的服务器。
收件方服务器确认可以建立连接后,双发就可以开始通信。
(二)POP3:
是把邮件从电子邮箱服务器中传输到本地计算机客户端的协议。
POP3(PostOfficeProtocol3)即邮局协议的第3个版本,它是规定个人计算机如何连接到互联网上的邮件服务器进行收发邮件的协议。
它是因特网电子邮件的第一个离线协议标准,POP3协议允许用户从服务器上把邮件存储到本地主机(即自己的计算机)上,同时根据客户端的操作删除或保存在邮件服务器上的邮件,而POP3服务器则是遵循POP3协议的接收邮件服务器,用来接收电子邮件的。
(三)IMAP:
InternetMailAccessProtocol(交互式邮件存取协议)。
它的主要作用是邮件客户端(例如MSOutlookExpress)可以通过这种协议从邮件服务器上获取邮件的信息,下载邮件等。
IMAP协议运行在TCP/IP协议之上,使用的端口是143。
它与POP3协议的主要区别是用户可以不用把所有的邮件全部下载,可以通过客户端直接对服务器上的邮件进行操作。
IMAP协议比较自由的功能是用户可以维护自己在服务器上的邮件目录;可以直接抓取邮件的特定部分(例如只有文本)。
IMAP的一个与POP3的区别是:
IMAP它只下载邮件的主题,并不是把所有的邮件内容都下载下来,而是你邮箱当中还保留着邮件的副本,没有把你原邮箱中的邮件删除,你用邮件客户软件阅读邮件时才下载邮件的内容。
(5)Java一键实现邮件发送:
(QQ邮箱为例,一会封装用网易邮箱(很多坑))
(一)先导入库:
--poi-->
org.apache.poi
poi
3.15
--zdkadd2017-5-16-->
org.apache.poi
poi-ooxml
3.15
--Java邮件操作类-->
javax.mail
mail
1.4.5
(二)给发信的邮箱申请协议服务开通
(三)一键复制即可实现:
我们需要修改的东西:
邮箱、邮箱服务器授权码
importjavax.mail.Session;
importjavax.mail.Transport;
importjavax.mail.internet.InternetAddress;
importjavax.mail.internet.MimeMessage;
importjava.util.Date;
importjava.util.Properties;
/**
*Createdby符柱成on2017/6/6.
*/
publicclassJavaMailSendTest{
//发件人的邮箱和密码(替换为自己的邮箱和密码)
//PS:
某些邮箱服务器为了增加邮箱本身密码的安全性,给SMTP客户端设置了独立密码(有的邮箱称为“授权码”),
//对于开启了独立密码的邮箱,这里的邮箱密码必需使用这个独立密码(授权码)。
publicstaticStringmyEmailAccount="751197996@";//我们申请服务的邮箱
publicstaticStringmyEmailPassword="";//这个就要填上我们刚刚拿到的授权码
//发件人邮箱的SMTP服务器地址,必须准确,不同邮件服务器地址不同,一般(只是一般,绝非绝对)格式为:
//网易163邮箱的SMTP服务器地址为:
;qq邮箱的SMTP服务器地址:
publicstaticStringmyEmailSMTPHost="";
//收件人邮箱(替换为自己知道的有效邮箱)
publicstaticStringreceiveMailAccount="1433317518@";
publicstaticvoidmain(String[]args)throwsException{
//1.创建参数配置,用于连接邮件服务器的参数配置
Propertiesprops=newProperties();//参数配置
props.setProperty("mail.transport.protocol","smtp");//使用的协议(JavaMail规范要求)
props.setProperty("mail.smtp.host",myEmailSMTPHost);//发件人的邮箱的SMTP服务器地址
props.setProperty("mail.smtp.auth","true");//需要请求认证
//PS:
某些邮箱服务器要求SMTP连接需要使用SSL安全认证(为了提高安全性,邮箱支持SSL连接,也可以自己开启),
//如果无法连接邮件服务器,仔细查看控制台打印的log,如果有有类似“连接失败,要求SSL安全连接”等错误,
//打开下面/*...*/之间的注释代码,开启SSL安全连接。
/*
//SMTP服务器的端口(非SSL连接的端口一般默认为25,可以不添加,如果开启了SSL连接,
//需要改为对应邮箱的SMTP服务器的端口,具体可查看对应邮箱服务的帮助,
//QQ邮箱的SMTP(SLL)端口为465或587,其他邮箱自行去查看)
finalStringsmtpPort="465";
props.setProperty("mail.smtp.port",smtpPort);
props.setProperty("mail.smtp.socketFactory.class",".ssl.SSLSocketFactory");
props.setProperty("mail.smtp.socketFactory.fallback","false");
props.setProperty("mail.smtp.socketFactory.port",smtpPort);
*/
finalStringsmtpPort="465";
props.setProperty("mail.smtp.port",smtpPort);
props.setProperty("mail.smtp.socketFactory.class",".ssl.SSLSocketFactory");
props.setProperty("mail.smtp.socketFactory.fallback","false");
props.setProperty("mail.smtp.socketFactory.port",smtpPort);
//2.根据配置创建会话对象,用于和邮件服务器交互
Sessionsession=Session.getDefaultInstance(props);
session.setDebug(true);//设置为debug模式,可以查看详细的发送log
//3.创建一封邮件
MimeMessagemessage=createMimeMessage(session,myEmailAccount,receiveMailAccount);
//4.根据Session获取邮件传输对象
Transporttransport=session.getTransport();
//5.使用邮箱账号和密码连接邮件服务器,这里认证的邮箱必须与message中的发件人邮箱一致,否则报错
//
//PS_01:
成败的判断关键在此一句,如果连接服务器失败,都会在控制台输出相应失败原因的log,
//仔细查看失败原因,有些邮箱服务器会返回错误码或查看错误类型的链接,根据给出的错误
//类型到对应邮件服务器的帮助网站上查看具体失败原因。
//
//PS_02:
连接失败的原因通常为以下几点,仔细检查代码:
//
(1)邮箱没有开启SMTP服务;
//
(2)邮箱密码错误,例如某些邮箱开启了独立密码;
//(3)邮箱服务器要求必须要使用SSL安全连接;
//(4)请求过于频繁或其他原因,被邮件服务器拒绝服务;
//(5)如果以上几点都确定无误,到邮件服务器网站查找帮助。
//
//PS_03:
仔细看log,认真看log,看懂log,错误原因都在log已说明。
transport.connect(myEmailAccount,myEmailPassword);
//6.发送邮件,发到所有的收件地址,message.getAllRecipients()获取到的是在创建邮件对象时添加的所有收件人,抄送人,密送人
transport.sendMessage(message,message.getAllRecipients());
//7.关闭连接
transport.close();
}
/**
*创建一封只包含文本的简单邮件
*
*@paramsession和服务器交互的会话
*@paramsendMail发件人邮箱
*@paramreceiveMail收件人邮箱
*@return
*@throwsException
*/
publicstaticMimeMessagecreateMimeMessage(Sessionsession,StringsendMail,StringreceiveMail)wsException{
//1.创建一封邮件
MimeMessagemessage=newMimeMessage(session);
//2.From:
发件人
message.setFrom(newInternetAddress(sendMail,"符柱成主页","UTF-8"));
//3.To:
收件人(可以增加多个收件人、抄送、密送)
message.setRecipient(MimeMessage.RecipientType.TO,newInternetAddress(receiveMail,"XX用户","UTF-8"));
//4.Subject:
邮件主题
message.setSubject("重要通知啊,老哥","UTF-8");
//5.Content:
邮件正文(可以使用html标签)
message.setContent("辅助:
打声招呼而已","text/html;charset=UTF-8");
//6.设置发件时间
message.setSentDate(newDate());
//7.保存设置
message.saveChanges();
returnmessage;
}
}
(6)Java邮件封装和异步实现:
(网易邮箱为例)
为什么要异步?
?
邮件和短信都要经过复杂的网络通信,这就意味着很可能极其耗时,使用同步方式,很容易导致主线程卡死,导致极差的体验。
所以,我们应该以异步方式去执行此业务,然后直接告诉用户已经发送(发送情况失败毕竟很少见)。
(一)定接口与实现类:
publicinterfaceEmailService{
/*
*hisEmail收件人email
*subject主题(标题)
*content内容(文本)
*/
voidsendEmail(StringhisEmail,Stringsubject,Stringcontent);
}
记得配置好config.properties。
分别是发件人邮箱(开通SMTP服务的),授权码,邮件名字
SENDER_MAILBOX=?
?
?
MAIL_PASSWPRD=?
?
?
MAIL_NAME=BSS\u7CFB\u7EDF\u90AE\u7BB1
可以看到跟使用qq邮箱有很大区别,但是必须如此配置使用,必须使用Authenticator去验证
publicclassEmailServiceImplimplementsEmailService{
privatestaticfinalLoglog=LogFactory.getLog(EmailServiceImpl.class);
//发件人的邮箱和密码(替换为自己的邮箱和密码)
//对于开启了独立密码的邮箱,这里的邮箱密码必需使用这个独立密码(授权码)。
publicstaticStringmyEmailAccount="";
publicstaticStringmyEmailPassword="";
publicstaticStringmyEmailName="";
//qq邮箱的SMTP服务器地址:
publicstaticStringmyEmailSMTPHost="";
static{
//博主自己封装了一个获取本地文件的配置参数方式,大家可以参考使用。
针对config.properties的,想改别的文件请大家自行修改。
try{
myEmailAccount=Config.getConfigValue("SENDER_MAILBOX");
myEmailPassword=Config.getConfigValue("MAIL_PASSWPRD");
myEmailName=Config.getConfigValue("MAIL_NAME");
System.out.println(myEmailAccount);
System.out.println(myEmailPassword);
System.out.println(myEmailName);
}catch(Exceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
@Override
publicvoidsendEmail(StringhisEmail,Stringsubject,Stringcontent){
System.out.println("myEmailAccount:
"+myEmailAccount);
System.out.println("myEmailPassword:
"+myEmailPassword);
try{
//1.创建参数配置,用于连接邮件服务器的参数配置
finalPropertiesprops=newProperties();//参数配置
props.p