300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > javamail模拟邮箱功能--邮件回复-中级实战篇【邮件回复方法】(javamail API电子邮件实例)

javamail模拟邮箱功能--邮件回复-中级实战篇【邮件回复方法】(javamail API电子邮件实例)

时间:2022-07-13 20:23:56

相关推荐

javamail模拟邮箱功能--邮件回复-中级实战篇【邮件回复方法】(javamail API电子邮件实例)

引言:

JavaMai下载地址l jar包:/products/javamail/downloads/index.html

此篇是紧随上篇文章而封装出来的,阅读本篇章建议先阅读上一篇 –>javamail模拟邮箱功能获取邮件内容-中级实战篇【内容|附件下载方法】(javamail API电子邮件实例)

在上一篇中,讲解了邮件获取内容的两个方法(HTML和附件),简单介绍了邮件发送和内容获取的相同和不同之处,并且引入了新类–>javax.mail.Store:容器类。同时对SMTP和POP3协议对应的大致功能进行说明。

本章节将来演示javamail的邮件回复功能,本来以为API会提供一个自动封装好的方法来供调用,找了好久,并网上查阅了不少资料,原来根本都没有实现回复功能,API只有一个方法:reply(Boolean)方法,来提示邮件回复时的收件人信息,但这个方法有点鸡肋,他仅在发送邮件的时候,除非你指明了回复时的邮件地址,才能回去到,并且在回复邮件时,完全可以新增收件人。

思路:

既然API没有给我们直接回复的方法,那就发挥我们自强不息的精神吧(吼吼),那么该怎么回复一封邮件呢?

首先我们拿到要回复的邮件。(这就用到了邮件获取的方法)

提取邮件的各个部件信息。(收件人、发件人、发件时间、主题、内容等,你要在回复里面显示的都可以提取)

创建一个新邮件。(根据提出出来的信息,组装一个新邮件,如主题可以在原来上面加个:Re:标识,内容一般为:新内容+原邮件内容)

发送自己组装的邮件。(又用到了邮件的发送方法)

看完思路总结,立马清晰了,原来邮件回复就是邮件查看和发送的合体!

示例结构:

本篇示例代码分了5类(把前一章节的获取业务类进行拆分,并且新增回复业务类,其余3类没有变动)

EmailEntity 类 邮件基础父类 【前三类都和之前章节相同】

EmailServiceEnity 类 邮件服务支持类,继承邮件基础父类,并声明其他必要的私有属性(…)

SendEmailService 类邮件发送业务类,封装邮件发送的两个方法(HTML和附件)

LookEmailService 类 邮件接收|查看业务类,拆分为邮件获取和内容查看两部分(正文阅读和附件下载)

ReplyEmailService 类邮件回复业务类,封装邮件回复方法(获取邮件–>组装–>发送)。

实例代码演示:

****复制此五个类可直接跑测试****注释部分我尽可能详细讲解每个方法的作用****

EmailEntity 类

package com.cplatform.movie.back.javamail;import javax.mail.Authenticator;import javax.mail.PasswordAuthentication;/*** 邮件基础实体类*/public class EmailEntity extends Authenticator {/*** 用户名(登录邮箱)*/protected static String username;/*** 密码*/protected static String password;/*** 初始化邮箱地址和密码* @param username 邮箱* @param password 密码*/public EmailEntity(String username, String password) {EmailEntity.username = "这里填写发件箱地址";EmailEntity.password = "这里填写发件箱密码";}/*** 重写自我检验方法*/@Overrideprotected PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication(username, password);}String getPassword() {return password;}String getUsername() {return username;}public void setPassword(String password) {EmailEntity.password = password;}public void setUsername(String username) {EmailEntity.username = username;}}

EmailServiceEnity 类

package com.cplatform.movie.back.javamail;import java.io.UnsupportedEncodingException;import java.util.Properties;import javax.mail.Message;import javax.mail.MessagingException;import javax.mail.NoSuchProviderException;import javax.mail.Session;import javax.mail.Transport;import javax.mail.internet.InternetAddress;import javax.mail.internet.MimeMessage;import com.cplatform.movie.back.javamail.SimpleEmailFunction.MyAuthenricator;/*** 邮件服务支持类*/public class EmailServiceEnity extends EmailEntity{// java.util.propertis 类private transient Properties props;// 一个邮件会话private transient Session session;// 邮件消息private transient MimeMessage message;// 邮件传输对象private Transport transport;// 邮件发送内容private String content;// 邮件内容格式private final String CONTENT_TYPE_HTML = "text/html;charset=utf-8";// 端口号 private final static String MAIL_PORT = "25";// 邮箱协议常量public static final String MAIL_PROTOCOL_SMTP = "smtp";public static final String MAIL_PROTOCOL_POP3 = "pop3";// 邮箱所使用的协议private String mailProtocol;// 邮箱服务器列表private String hostPort;//分//界/线/ /*** 实参构造* @param mailToaddress 收件人地址,多个以逗号隔开* @param content邮件内容* @throws MessagingException * @throws UnsupportedEncodingException */public EmailServiceEnity(String mailToaddress, String content, String mailProtocol) throws UnsupportedEncodingException, MessagingException {super(username, password);this.setMailProtocol(mailProtocol);this.setHostPort(mailProtocol +"."+ username.split("@")[1]);this.content = content;this.session = this.initSession();this.message = this.initMessage(this.getSession(), mailToaddress);// 这里需要对协议进行判断,SMTP:为发送协议(初始化Transport) POP3:则为接收协议(只能初始化Store,在接收邮件章节用到)if(this.getMailProtocol().equals(MAIL_PROTOCOL_SMTP)){this.transport = this.initTransport(this.getSession());}}/*** 初始化perps文件* @return*/public Properties initPrope() {// 初始化props文件props = new Properties();props.setProperty("mail.transport.protocol", this.getMailProtocol());//发送邮件协议props.put("mail.smtp.auth", "true"); //需要验证props.put("mail.smtp.host", this.getHostPort()); //服务器地址 return props;}/*** 初始化session会话* @return*/public Session initSession() {session = Session.getInstance(this.initPrope(),new MyAuthenricator(username, password));session.setDebug(true);return session;}/*** 初始化Message消息* @param session* @return* @throws MessagingException* @throws UnsupportedEncodingException*/public MimeMessage initMessage(Session session, String mailToaddress) throws MessagingException, UnsupportedEncodingException {message = new MimeMessage(session);// 设置发件人地址message.setFrom(new InternetAddress(username, "要显示的发件人名称"));// 设置邮件主题message.setSubject("主题:默认主题");// 设置邮件发送内容和内容的content-typemessage.setContent(content.toString(),this.CONTENT_TYPE_HTML);// 设置邮件接收人地址if(mailToaddress.trim().length() > 0) {String [] address = mailToaddress.split(",");for(int i=0; i<address.length; i++) {// addRecipient(该方法为添加收件人列表,参数一为类型:TO-收件人,CC-抄送,参数二为一个邮件地址)message.addRecipient(Message.RecipientType.TO, new InternetAddress(address[i].trim()));// 下面方法为传递一个收件地址字符串 (二者方法任选其一即可)message.addRecipients(, address[i].trim());}}return message;}/*** 初始化Transport* @param session* @return* @throws NoSuchProviderException*/public Transport initTransport(Session session) throws NoSuchProviderException {transport = session.getTransport(); return transport;}/***************** 提供必要的get set方法支持 ************飘逸的分割线****************/public Session getSession() {return session;}public void setSession(Session session) {this.session = session;}public MimeMessage getMessage() {return message;}public void setMessage(MimeMessage message) {this.message = message;}public Properties getProps() {return props;}public String getContentTypeHtml() {return CONTENT_TYPE_HTML;}public static String getMailPort() {return MAIL_PORT;}public String getHostPort() {return hostPort;}public void setHostPort(String hostPort) {this.hostPort = hostPort;}public Transport getTransport() {return transport;}public void setTransport(Transport transport) {this.transport = transport;}public void setProps(Properties props) {this.props = props;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public String getCONTENT_TYPE_HTML() {return CONTENT_TYPE_HTML;}public static String getMailProtocolSmtp() {return MAIL_PROTOCOL_SMTP;}public static String getMailProtocolPop3() {return MAIL_PROTOCOL_POP3;}public String getMailProtocol() {return mailProtocol;}public void setMailProtocol(String mailProtocol) {this.mailProtocol = mailProtocol;}}

SendEmailService 类

package com.cplatform.movie.back.javamail;import java.io.File;import java.io.UnsupportedEncodingException;import javax.activation.DataHandler;import javax.activation.FileDataSource;import javax.mail.BodyPart;import javax.mail.Message;import javax.mail.MessagingException;import javax.mail.Multipart;import javax.mail.internet.MimeBodyPart;import javax.mail.internet.MimeMultipart;import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimeUtility;/*** 邮件发送业务类*/public class SendEmailService {private EmailServiceEnity serviceEnity;/*** 发送HTML内容邮件 (包括TEXT格式)* @throws MessagingException */public void sendHtmlOrText() throws MessagingException {this.send();}/*** 附件发送 * @param file java.io.File* @param fileName 附件名* @throws MessagingException* @throws UnsupportedEncodingException*/public void sendFile(File file, String fileName) throws MessagingException, UnsupportedEncodingException {// 获得Message实例Message message = serviceEnity.getMessage();// 创建multipart容器用来容纳bodyPart(部件)Multipart multipart = new MimeMultipart();/*** 创建一个BodyPart内容报文* 每个消息都有多个部分组成,每个部分是一个BodyPart报文部分,多个BodyPart部分又同时组成一个Multipart的容器*/BodyPart messageBodyPart = new MimeBodyPart();// 设置该报文的内容messageBodyPart.setContent(serviceEnity.getContent(),serviceEnity.getCONTENT_TYPE_HTML());// 添加bodyPart报文部分到multiPart容器multipart.addBodyPart(messageBodyPart);// 创建一个附件报文messageBodyPart = new MimeBodyPart();// 文件源FileDataSource fds = new FileDataSource(file);// 设置邮件的内含附件 (设置数据源为复件)messageBodyPart.setDataHandler(new DataHandler(fds));// 设置附件的文件名,需进行编码,否则文件名会乱码messageBodyPart.setFileName(MimeUtility.encodeText(fileName));// 添加到容器multipart.addBodyPart(messageBodyPart);// 添加报文容器到消息实例message.setContent(multipart);// 发送消息this.send();}/*** 发送* 推荐使用方法一,因为方法二如果收件人为多个的话,会为每个人都打开一个Transport通道再关闭* 而方法一在发送过程中一直保持连接通常,所有操作完成后才关闭* @throws MessagingException*/public void send() throws MessagingException {Message message = serviceEnity.getMessage();// 方法一serviceEnity.getTransport().connect();serviceEnity.getTransport().sendMessage(message, message.getAllRecipients());serviceEnity.getTransport().close();// 方法二// Transport.send(this.getMessage());}// main 方法测试public static void main(String[] args) {SendEmailService service;EmailServiceEnity enity;// 多个收件人中间以逗号间隔String mailToaddress = "418874847@,12450374@";// 正文(内容)部分String content = "点击进入» <a href='/liuyitian'>刘一天的博客</a>";try {service = new SendEmailService();enity = new EmailServiceEnity(mailToaddress, content, EmailServiceEnity.MAIL_PROTOCOL_SMTP);service.setServiceEnity(enity);service.sendHtmlOrText(); // 测试HTML文本/*** 切勿使用同一个EmailServiceEnity实例来发送不同内容,如有需要就再初始化一个新实例(否则附件发送失败且乱码)* 因为每个实例在发送完邮件后就会关闭Transport*/enity = new EmailServiceEnity(mailToaddress, content, EmailServiceEnity.MAIL_PROTOCOL_SMTP);service.setServiceEnity(enity);// 传入一个绝对位置的文件路径File file = new File("d:/data/adimg/1022/09/ad_1022094708943.jpg");service.sendFile(file,"测试附件发送.jpg"); // 测试复件发送} catch (UnsupportedEncodingException e1) {e1.printStackTrace();} catch (MessagingException e1) {e1.printStackTrace();}}public EmailServiceEnity getServiceEnity() {return serviceEnity;}public void setServiceEnity(EmailServiceEnity serviceEnity) {this.serviceEnity = serviceEnity;}}

LookEmailService 类(有功能的细分操作)

package com.cplatform.movie.back.javamail;import java.io.DataInputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.UnsupportedEncodingException;import javax.mail.BodyPart;import javax.mail.Folder;import javax.mail.Message;import javax.mail.MessagingException;import javax.mail.Multipart;import javax.mail.Store;import javax.mail.internet.MimeUtility;/*** 查看|接收邮件业务类*/public class LookEmailService {private transient EmailServiceEnity emailService;private transient Folder folder;private transient Store store;// 初始化对象时附带初始化必要参数public LookEmailService() throws UnsupportedEncodingException, MessagingException {this.initStoreAndFolder();}// 主方法,这里演示单个邮件的内容读取和附件下载public void lookEmail() throws MessagingException, IOException, InterruptedException {// 获得邮件Message[] messages = this.getAllMessage(); // 方法一,得到全部邮件数组Message message = this.getMessageByIndex(messages.length); // 方法二System.out.println("邮件接收时间:"+message.getSentDate());System.out.println("邮件发送者:"+message.getFrom()[0]);System.out.println("邮件主题:"+message.getSubject());System.out.println("邮件内容:"+message.getContent()); // 内存地址System.out.println("***********************飘逸的分割线*****************************");/*** 判断内容是否由多部件组成*/if(!message.getContentType().contains("multipart/")) {return;}// 得到邮件的Multipart(内容总部件--【包涵附件】)Multipart multipart = (Multipart) message.getContent();int count = multipart.getCount(); // 部件个数for(int i=0; i<count; i++) {// 单个部件注意:单个部件有可能又为一个Multipart,层层嵌套BodyPart part = multipart.getBodyPart(i);// 单个部件类型String type = part.getContentType().split(";")[0];/*** 类型众多,逐一判断,其中TEXT、HTML类型可以直接用字符串接收,其余接收为内存地址* 可能不全,如有没判断住的,请自己打印查看类型,在新增判断*/if(type.equals("multipart/alternative")) { // HTML (文本和超文本组合)System.out.println("超文本:" + part.getContent().toString());}else if(type.equals("text/plain")) { // 纯文本System.out.println("纯文本:" + part.getContent().toString());}else if(type.equals("text/html")){ // HTML标签元素System.out.println("HTML元素:" + part.getContent().toString());}else if(type.equals("multipart/related")){ // 内嵌资源 (包涵文本和超文本组合)System.out.println("内嵌资源:" + part.getContent().toString());}else if(type.contains("application/")) { // 应用附件 (zip、xls、docx等)System.out.println("应用文件:" + part.getContent().toString());}else if(type.contains("image/")) { // 图片附件 (jpg、gpeg、gif等)System.out.println("图片文件:" + part.getContent().toString());}/*****************************************获取邮件内容方法***************************************************//*** 附件下载* 这里针对image图片类型附件做下载操作,其他类型附件同理*/if(type.contains("image/")) {// 打开附件的输入流DataInputStream in = new DataInputStream(part.getInputStream());// 一个文件输出流FileOutputStream out = null;// 获取附件名String fileName = part.getFileName();// 文件名解码fileName = MimeUtility.decodeText(fileName);// 根据附件名创建一个File文件File file = new File("d:/data/" + fileName);// 查看是否有当前文件Boolean b = file.exists();if(!b) {out = new FileOutputStream(file);int data;// 循环读写while((data=in.read()) != -1) {out.write(data);}System.out.println("附件:【" + fileName + "】下载完毕,保存路径为:" + file.getPath());}// 关流if(in != null) {in.close();}if(out != null) {out.close();}}/*** 获取超文本复合内容* 他本是又是一个Multipart容器* 此时邮件会分为TEXT(纯文本)正文和HTML正文(HTML标签元素)*/if(type.equals("multipart/alternative")) {Multipart m = (Multipart) part.getContent();for (int k=0; k<m.getCount(); k++) {if(m.getBodyPart(k).getContentType().startsWith("text/plain")) {// 处理文本正文System.out.println("TEXT文本内容:"+"\n" + m.getBodyPart(k).getContent().toString().trim()+"\n");} else {// 处理 HTML 正文System.out.println("HTML文本内容:"+"\n" + m.getBodyPart(k).getContent()+"\n");}}}}/*** 最后千万别忘记了关闭*/folder.close(false); // false为不更新邮件,true为更新,一般在删除邮件后使用store.close();}/*** 返回一个指定条目的邮件* @return* @throws MessagingException */public Message getMessageByIndex(int index) throws MessagingException {return folder.getMessage(index);}/*** 返回邮箱所有邮件* @param args* @throws MessagingException */public Message[] getAllMessage() throws MessagingException {return folder.getMessages();}/*** 返回指定区间(起始条目和结束条目)的邮件* @param args* @throws MessagingException */public Message[] getMessageBySpace(int start, int end) throws MessagingException {return folder.getMessages(start, end);}/*** 初始化Store连接和获取Folder邮件夹* @throws MessagingException * @throws UnsupportedEncodingException */public void initStoreAndFolder() throws UnsupportedEncodingException, MessagingException {/*** 接收邮件时,邮箱的协议为POP3,SMTP为邮件传输协议,这里别搞混了* 并且检查你的邮箱设置POP3功能是否开启*/emailService = new EmailServiceEnity("", "",EmailServiceEnity.MAIL_PROTOCOL_POP3);/*** javax.mail.Store类用于连接邮件接收服务器,并访问邮件接收服务器上的各个邮箱夹* javax.mail.Folder类表示邮件夹* 通过一个Session我们可以拿到一个邮箱对应的Store*/store = emailService.getSession().getStore(emailService.getMailProtocol());store.connect(emailService.getHostPort(), EmailServiceEnity.username, EmailServiceEnity.password);/***通过Store拿到收件箱文件夹* INBOX 标识获取到邮件夹里的收件箱 (对于POP3协议仅INBOX可用--蛋疼哦) * 并以只读方式打开收件箱*/folder = store.getFolder("INBOX");folder.open(Folder.READ_ONLY);}// main 方法简单测试public static void main(String[] args) {try {new LookEmailService().lookEmail();} catch (IOException e) {e.printStackTrace();} catch (MessagingException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}/***************GET********************SET***********************/public EmailServiceEnity getEmailService() {return emailService;}public void setEmailService(EmailServiceEnity emailService) {this.emailService = emailService;}public Store getStore() {return store;}public void setStore(Store store) {this.store = store;}public Folder getFolder() {return folder;}public void setFolder(Folder folder) {this.folder = folder;}}

ReplyEmailService 类 (邮件回复业务类)

package com.cplatform.movie.back.javamail;import java.io.IOException;import java.io.UnsupportedEncodingException;import javax.mail.Address;import javax.mail.Message;import javax.mail.MessagingException;import javax.mail.internet.InternetAddress;/*** 邮件回复业务类*/public class ReplyEmailService {// 服务实体类private transient EmailServiceEnity emailService;// 回复内容private transient String content;/*** 邮件回复方法* 思路:先获取要回复的邮件,然后获取邮件的各个详情,把详情附加给新建邮件,发送* @throws MessagingException * @throws IOException */public void replyEmail () throws MessagingException, IOException {// 获取邮件,和查看邮件相同,调用方法即可LookEmailService lookEmail = new LookEmailService();emailService = new EmailServiceEnity("", "",EmailServiceEnity.MAIL_PROTOCOL_POP3);lookEmail.setEmailService(emailService);Message message = lookEmail.getMessageByIndex(lookEmail.getAllMessage().length);/*************上面为获取邮件************到此处是一个分水岭****************下面为发送邮件****************/Message reply = this.newReplyMessage(message);// 布尔值,true为回复给所有人,false为只回复给发送者reply.reply(true);// 发送回复emailService.getTransport().connect();emailService.getTransport().sendMessage(reply, reply.getAllRecipients());emailService.getTransport().close();}/*** 组装要回复的邮件* @param message* @return* @throws MessagingException* @throws IOException*/public Message newReplyMessage(Message message) throws MessagingException, IOException {// 出新初始化一个服务类,因为之前为获取邮件,协议为POP3,当前要发送邮件,协议为SMTPemailService = new EmailServiceEnity("", "", EmailServiceEnity.MAIL_PROTOCOL_SMTP);// 新创建一个邮件Message reply = emailService.getMessage();// 获取原邮件的发件人--》为新邮件的接收人Address[] addressTo = message.getFrom();// 获取原邮件内容(暂支持文本和HTML单部件,多部件另需递归循环原邮件,并新增)Object content = message.getContent();// 获取原邮件主题String subObject = message.getSubject();// 获取邮件发送时间String date = message.getSentDate().toString();/** 组装新邮件*/// 设置回复内容,新内容+原文reply.setContent(this.content + "<br/><br/><br/>" + date +","+InternetAddress.toString(addressTo) + "写到:<br/>> " + content, "text/html;charset=utf-8");// 设置邮件回复主题reply.setSubject("Re:" + subObject);// 设置收件人:原发件人reply.addRecipients(Message.RecipientType.TO, addressTo);return reply;}// 简单main方法测试public static void main(String[] args) {try {ReplyEmailService replySend = new ReplyEmailService();replySend.setContent("你好,邮件已收到! <a href='/liuyitian'><<--点击进入我的博客-->></a>");replySend.replyEmail();} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (MessagingException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}/**********************GET***********************SET****************************/public EmailServiceEnity getEmailService() {return emailService;}public void setEmailService(EmailServiceEnity emailService) {this.emailService = emailService;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}}

代码部分都是在之前的基础上进行累加的,没变化的类直接进行折叠。到目前:发、收、回基本解决。

本章小结:

对收取邮件业务类代码再次进行拆分,使获取邮件方法更加复用。

啰嗦了一点模块细分,主要还是简单责任原则,方便解耦和和可增强扩展。

回复邮件时,对于原邮件内容并没有过多判断,还请自己实现,参考邮件收取业务类方法即可。

其他细节:(对收发时使用的协议要步步明确,以免引起异常)。

未涉及:其他功能:(如:标记邮件、删除等)…之后陆续更新。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。