电子邮件早已成为工作生活中不可缺少的部分,每个工作的人都会有自己的私人邮箱或企业邮箱,用来协助我们处理生活事务以及实现工作中的交流。
今天主要通过简单的示例,了解在java中如何使用api来完成邮件的接收与发送。
通过该篇文章我们可以有如下收获:
了解基于java的电子邮件客户端的实现方式了解常见的邮箱如何集成认识邮箱中的imap与pop协议适用场景邮件和短信很像,将信息发送到目的用户,不需要用户在线,基于邮件服务器,完成消息的存储与转发。一般公司都会有自己的企业邮箱,主要也是为了保证数据的安全性。可能你平时在注册网站时,需要通过邮件来接收验证消息完成认证流程;或者每天打开邮箱收到的各种订阅消息等等。
基于电子邮件的通信与交流接收验证消息,实现用户认证发送邮件提供消息通知说明电子邮件在internet上发送和接收的原理与我们通过邮局发信件非常相类似:首先要找到任何一个邮局,填写邮件收件人姓名、地址等信息, 之后信件就会寄到收件人所在地的邮局,对方需要到相应的邮局才能取出信件。同样,在发送电子邮件时,邮件是由邮件发送服务器发出, 根据收信人的地址匹配目的邮件接收服务器,收信人收取邮件需要访问这个服务器才能取件。
邮件的发送与接收都需要基于特定的通信协议,发邮件时基于smtp协议,收邮件时基于pop3、imap协议。
smtp
smtp 的全称是“simple mail transfer protocol”,即简单邮件传输协议,是用于发送电子邮件的协议。它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。smtp 协议属于 tcp/ip 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。smtp 服务器就是遵循 smtp 协议的发送邮件服务器。imap
imap(internet message access protocol)internet邮件访问协议,是用于接收电子邮件的协议。imap不用对服务器上面的邮件进行全部下载(根据实际需要进行下载),可以通过邮件客户端对邮件进行操作;imap提供了webmail与邮件客户端之间的双向通信,以及客户端上的操作(如阅读、删除、移动邮件等)。pop3
pop3(post office protocol version 3)邮局协议的第3个版本,同样用于接收电子邮件的协议。pop3可以让你下载邮件服务器上的邮件(下载所有未读邮件),在邮件从服务器发送到电脑的同时删除邮件服务器上的邮件(目前很多邮件服务器都支持“下载邮件,不删除邮件,或者发出提醒”)。pop允许电子邮件客户端下载服务器上的邮件,但是您在电子邮件客户端的操作(如:移动邮件、标记已读等),这是不会反馈到服务器上的, 比如:您通过电子邮件客户端收取了qq邮箱中的3封邮件并移动到了其他文件夹,这些移动动作是不会反馈到服务器上的,也就是说,qq邮箱服务器上的这些邮件是没有同时被移动的。但是imap就不同了,电子邮件客户端的操作都会反馈到服务器上,您对邮件进行的操作(如:移动邮件、标记已读等),服务器上的邮件也会做相应的动作。也就是说,imap是“双向”的。同时,imap可以只下载邮件的主题,只有当您真正需要的时候,才会下载邮件的所有内容。
如果感兴趣可以深入了解这几个协议的具体实现与规范,这里我们只用知道,与邮箱服务器对接时,是基于这几个协议来实现通信,什么时候用什么协议即可。后面示例中会有用到。
邮箱与协议如果要完成邮件的发送,我们需要知道用户通过服务器将邮件发送给 谁 ,这里的用户指的是发件方,需要明确我们的发件地址, 谁即对方的邮箱地址,邮箱地址主要邮3个部分组成, 用户名 @ 邮件服务器域名 ,比如123456@qq.com,tom@gmail.com等等, 上面说到的服务器与域名对应。
在编写示例前,需要先了解我们用到邮箱的一些信息,比如实现基于qq邮箱的邮件发送以及收取时,我们必须知道其邮箱服务器对应的协议服务地址以及端口, 下面是几个常见的协议信息:
126邮箱协议类型协议功能服务器地址非ssl端口ssl端口号
smtp 发送邮件 smtp.126.com 25 465、994
pop 接收邮件 pop.126.com 110 995
imap 接收邮件 imap.126.com 143 993
163邮箱协议类型协议功能服务器地址非ssl端口ssl端口号
smtp 发送邮件 smtp.163.com 25 465
pop 接收邮件 pop.163.com 110 995
imap 接收邮件 imap.163.com 143 993
qq邮箱协议类型协议功能服务器地址非ssl端口ssl端口号
smtp 发送邮件 smtp.qq.com 25 465、587
pop 接收邮件 pop.qq.com 110 995
imap 接收邮件 imap.qq.com 143 993
gmail邮箱协议类型协议功能服务器地址非ssl端口ssl端口号
smtp 发送邮件 smtp.gmail.com 465、587
pop 接收邮件 pop.gmail.com 995
imap 接收邮件 imap.gmail.com 993
实例在java中我们可以基于javamail api实现邮件的发送与读取,由于我使用的是jdk17,所以选用的是jakarta.mail.jar完成今天的示例。
在spring中同样提供了邮件的支持,我们可以在项目中通过引入spring-boot-starter-mail来集成,下面分别来看下如何实现邮件的收发功能。示例以qq邮件为例,比如我的邮箱地址为409835152@qq.com,下面来看看具体实现过程
发送邮件引入依赖 org.springframework.boot spring-boot-starter-mail ${spring-boot.version} 添加application配置spring: mail: host: smtp.qq.com port: 25 protocol: smtp username: 409835152@qq.com password: '******'这里主要配置了邮箱地址,和上面说到的协议类型、服务地址以及端口,最后还有一个密码,注意这里不是邮箱登录密码,我们需要单独申请,这个在各个邮箱中都有申请入口,比如qq邮箱中:
点击“管理服务”在新的页面中通过“生成授权码”按流程申请即可,注意不要泄露!!!
编写邮件发送服务@servicepublic class emailqqservice { @resource private javamailsender javamailsender; @resource private mailproperties mailproperties; public void sendemail(email email){ simplemailmessage simplemailmessage = new simplemailmessage(); simplemailmessage.setfrom(mailproperties.getusername()); //设置发送邮件账号 simplemailmessage.setto(email.getto()); //设置接收邮件的人,可以多个 simplemailmessage.setsubject(email.getsubject()); //设置发送邮件的主题 simplemailmessage.settext(email.gettext()); //设置发送邮件的内容 javamailsender.send(simplemailmessage); }}主要指定发送目标对象的邮箱地址,邮件主题以及邮件内容等即可。可以看到,基于spring提供的工具,邮件的发送变得非常简单。
邮件的接收在spring中没有提供这样的工具类,需要我们自己写:
@servicepublic class qqemailservice { public list receiveemail() throws messagingexception, ioexception { properties properties = configproperties(); store store = createstore( properties ); list emails = receive(store); store.close(); return emails; }}添加接收服务相关的配置,包括协议、服务地址、端口private properties configproperties(){ // 配置邮件服务器 properties properties = new properties(); properties.setproperty(mail.store.protocol, receivemailproperties.getprotocol()); properties.setproperty(mail.imap.host, receivemailproperties.gethost()); properties.setproperty(mail.imap.port, receivemailproperties.getport()); return properties; }创建session与storeprivate store createstore(properties properties) throws messagingexception { // 创建session实例对象 session session = session.getinstance( properties ); // 创建imap协议的store对象 store store = session.getstore(imap); // 连接邮件服务器 store.connect(mailproperties.getusername(), mailproperties.getpassword()); return store; }从服务器读取邮件private list receive(store store) throws messagingexception, ioexception { // 获得收件箱 folder folder = store.getfolder(inbox); // 以读写模式打开收件箱 folder.open(folder.read_write); // 各状态邮件数量 system.out.println(string.format(收件箱邮件总数:%s,其中,新邮件数:%s,未读邮件数:%s,,folder.getmessagecount(), folder.getunreadmessagecount(), folder.getnewmessagecount())); // 获得收件箱的邮件列表 message[] messages = folder.getmessages(folder.getmessagecount()-5, folder.getmessagecount()); system.out.println(------------------------开始解析邮件----------------------------------); list emaillist = new arraylist(); for (message message : messages) { email email = new email() .setfrom(arrays.stream(message.getfrom()).map(address - > ((internetaddress)address).getaddress()).collect(collectors.joining())) .setsubject(message.getsubject()) .setcontenttype(message.getcontenttype()) .setsenddate(message.getsentdate()) .setreceivedate(message.getreceiveddate()); system.out.println(string.format( >> >> > 邮件来自:%s,主题:%s,接收时间:%s, email.getfrom(), email.getsubject(), dateformatutils.format(email.getreceivedate(), dateformatutils.iso_8601_extended_datetime_format.getpattern())) ); email.setemailcontents(resolvemessage(message.getcontenttype(), message)); system.out.println(string.format(邮件内容:%s , email.getemailcontents())); emaillist.add(email); } // 关闭资源 folder.close(false); return emaillist; }解析邮件内容,邮件除了文字,还有图片,需要根据消息内容类型进行解析,当然发送消息的时候,同样支持各种类型的消息,具体可以javamailsender的实现类private list resolvemessage(string contenttype, message message) throws messagingexception, ioexception { list emailcontents = new arraylist(); resolvemessagecontent( message.getcontent(), message, emailcontent- >{ emailcontents.add(emailcontent); } );// return content.tostring(); return emailcontents; } private void resolvemessagecontent(object content, object parent, consumer emailcontentconsumer) throws messagingexception, ioexception { if( content instanceof string ){ emailcontentconsumer.accept( new emailcontent(emailcontent.type.text, (string) content) ); }else if( content instanceof mimemultipart){ mimemultipart multipart = (mimemultipart) content; int count = multipart.getcount(), index = -1; while ( count > ++index ){// 0:纯文本;1:html内容 bodypart bodypart = multipart.getbodypart(index); object partcontent = bodypart.getcontent(); resolvemessagecontent( partcontent, bodypart, emailcontentconsumer); } }else if( content instanceof base64decoderstream){ file file = new file(((imapbodypart) parent).getfilename()); ((base64decoderstream) content).transferto( new fileoutputstream( file ) ); emailcontentconsumer.accept( new emailcontent(emailcontent.type.file, file.getabsolutepath()) ); }else { system.out.println( >> >> >> >> >> >> >> >> 邮件内容类型: + content.getclass() ); emailcontentconsumer.accept( new emailcontent(emailcontent.type.text, content.tostring()) ); } }关闭storestore.close();代码有点多,但是流程不复杂且比较清晰。到这里一个简单的针对qq邮箱的邮件发送与接收示例就完成了。不管是收邮件还是发邮件其关键点是:
邮件收发对应的协议类型、服务地址、服务端口发送邮件用户的邮箱地址与授权码目标邮箱地址剩下的都是些简单api调用的过程
飞腾公司携手合作伙伴推出5G专网解决方案
小米扫地机器人拆解图及数据详细
LG在印度发布全新W系列手机 均内建4000mAh电池运行安卓9.0系统
通过单个PMIC为您的计算密集型应用处理器供电
水质检测器电路
在Java中如何使用API来完成邮件的接收与发送
视频结构化怎样实现突破
芯动科技风华系列芯片填补国内高性能数据中心显卡空白
张量类Tensor的实现
半入耳式蓝牙耳机推荐,半入耳蓝牙耳机推荐高性价比
地质灾害监测GNSS设备 GNSS接收机
LTC3865双输出降压型稳压器实现重负载条件下最高效率的应用
与传统母线保护方案对比弧光保护的优点
5G和Wi-Fi 6促进发展,预计到2025年全球联网设备的数量将翻一番多
莱迪思MachXO3 FPGA系列 助力新兴互连接口设计
和沐渥一起探讨:常用的控制板加工制造设备有哪些?
物联网风险意识在消费者和企业之间存在差异
十款智能遥控小车设计
索尼将发售限量版PS4 TPCast多用户无线VR套件正式面向欧洲发布
切比雪夫综合法的Matlab程序