zoukankan      html  css  js  c++  java
  • javamail模拟邮箱功能获取邮件内容-中级实战篇【内容|附件下载方法】(javamail API电子邮件实例)

    引言:

      JavaMail jar包下载地址:http://java.sun.com/products/javamail/downloads/index.html

      此篇是紧随上篇文章而封装出来的,阅读本篇章建议先阅读上一篇  -->javamail模拟邮箱功能发送电子邮件-中级实战篇【新增附件发送方法】(javamail API电子邮件实例)

      在上一篇中,讲解了邮件发送的两个基本方法(HTML和附件),并且引入了两个新类 Multipart  BodyPart 两类,整体结构比较紧凑,邮件的服务实体类和发送的业务方法耦合在一起,本篇章节中将再次对模块进行拆分,来实现简单责任原则。新优化为:邮件基础父类,邮件基础服务类,发送邮件业务类,收取邮件业务类,下面会为大家列出详细列表。

      既然本章节主要讲解的是邮件的接收|查看,就先来分析下邮件的发送和读取有什么本质上的区别(总结的不一定全面,请见谅~)。

      相同之处是:他们都需要初始化服务实体类里的各大属性,如:propertis文件、Message消息、Session邮件会话等,在操作附件时都用到了io流的操作。

      不同之处是:邮件发送会用到Transport通道,协议使用的是SMTP协议,而邮件接收则用到的是Store容器类,且协议一般广泛使用POP(最新为POP3)协议,这种协议需要用户自定义设置里面开启才能使用,并且目前该协议只支持收件箱的读取(吐槽下 ‘-.-’ ,要能读私密文件夹,那岂不***)。

    javax.mail.Store容器类,由它来访问用户保存在服务器上的各个邮件夹

    示例结构:

      本篇示例代码分了4类(都是在前一章节基础上进行拆分的,并且把test测试都融合在各自的业务类里面【简单main方法】)

    • EmailEntity  类  邮件基础父类 【和上一章相同     点我查看上一章节 
    • EmailServiceEnity  类   邮件服务支持类,继承邮件基础父类,并声明其他必要的私有属性(propertis文件、Message消息、Session邮件会话等
    • SendEmailService  类 邮件发送业务类,封装邮件发送的两个方法(HTML和附件)
    • LookEmailService  类   邮件接收|查看业务类,封装邮件查看方法(正文阅读和附件下载)

     实例代码演示:

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

    EmailEntity  类 (有复制之前章节的可忽略此类)

    package com.cplatform.movie.back.javamail;
    
    import javax.mail.Authenticator;
    import javax.mail.PasswordAuthentication;
    
    /**
     * 邮件基础实体类
     * @author liuyt
     * @date  2014-10-24 下午2:12:10
     */
    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 = "这里填写发件箱密码";
        }
    
        /**
         * 重写自我检验方法
         */
        @Override
        protected 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;
        }
    }
    EmailEntity 基础实体类,点击可展开阅读

    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;
    
    /**
     * 邮件服务支持类
     * @author liuyt
     * @date  2014-10-24 下午2:11:38
     */
    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-type
            message.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(Message.RecipientType.CC, 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;
    
    /**
     * 邮件发送业务类
     * @author liuyt
     * @date  2014-10-26 上午11:17:45
     */
    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@qq.com,12450374@qq.com";
            
            // 正文(内容)部分
            String content = "点击进入» <a href='http://www.cnblogs.com/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/20141022/09/ad_20141022094708943.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 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;
    
    /**
     * 查看|接收邮件业务类
     * @author liuyt
     * @date  2014-10-24 下午2:04:48
     */
    public class LookEmailService {
        private transient EmailServiceEnity emailService;
        
        public void lookEmail() throws MessagingException, IOException, InterruptedException {
            
            /**
             * 接收邮件时,邮箱的协议为POP3,SMTP为邮件传输协议,这里别搞混了
             * 并且检查你的邮箱设置POP3功能是否开启
             */
            emailService = new EmailServiceEnity("", "",EmailServiceEnity.MAIL_PROTOCOL_POP3);
            
            /**
             *  javax.mail.Store类用于连接邮件接收服务器,并访问邮件接收服务器上的各个邮箱夹
             *  javax.mail.Folder类表示邮件夹
             *  通过一个Session我们可以拿到一个邮箱对应的Store
             */
            Store store = emailService.getSession().getStore(emailService.getMailProtocol());
            store.connect(emailService.getHostPort(), EmailServiceEnity.username, EmailServiceEnity.password);
            
            /**
             *     通过Store拿到收件箱文件夹
             *  INBOX 标识获取到邮件夹里的收件箱  (对于POP3协议仅INBOX可用--蛋疼哦) 
             *  并以只读方式打开收件箱
             */
            Folder folder = store.getFolder("INBOX");
            folder.open(Folder.READ_ONLY);
            
            /**
             * 读取到的邮件是存在Message里面,有不同的获取方法
             * 方法一:获取的是全部邮件,返回一个Message数组
             * 方法二:获取指定条目的邮件(1表示邮箱里面的第一封邮件,也就是最早的一封)
             * 还有很多方法,如起始位置和结束位置......不一一列举
             */
             Message[] messages = folder.getMessages();    // 方法一,得到全部邮件数组
             Message message = folder.getMessage(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("***********************飘逸的分割线*****************************");
             
             // 得到邮件的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文本内容:"+"
    " + m.getBodyPart(k).getContent().toString().trim()+"
    ");
                         } else {
                             // 处理 HTML 正文
                             System.out.println("HTML文本内容:"+"
    " + m.getBodyPart(k).getContent()+"
    ");
                         }
                    }
                 }
                 
             }
             
            /**
             * 最后千万别忘记了关闭
             */
            folder.close(false); // false为不更新邮件,true为更新,一般在删除邮件后使用
            store.close();
        }
        
        // 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();
            }
        }
    }

      到此处本章的代码部分全部贴出来了,篇幅可能有点长,只是把现有的功能都贴出来了,方便做对比。

    本章小结:

    • 对代码再次进行拆分,分为实体类、业务类支持类、发送业务类、接收业务类
    • 对邮件的两大功能(收/发)做简单对比
    • 简单责任原则,业务类里面能拆分的功能都进行拆分,各负其责,test方法和业务类融合,方便在本类进行测试
    • 对于邮件接收,由于内容Content-type类型众多,可能没有完全判断住(具体问题具体分析)
    • 常用的邮件协议:SMTP和POP3协议简单说明(详细还请度娘脑补)
    • 其他细节:(附件编码问题,正文格式声明,设置收件人方法【多种】)
    • 未涉及:其他功能。如:删除、回复、转发等(之后陆续更新)

     javamail API 系列篇:   

    1.  javamail模拟邮箱功能发送电子邮件-基础实战篇
    2.  javamail模拟邮箱功能发送电子邮件-中级实战篇【新增附件发送方法】
    3.  javamail模拟邮箱功能获取邮件内容-中级实战篇【内容|附件下载方法】 
    4.    javamail模拟邮箱功能--邮件回复-中级实战篇【邮件回复方法】
    5.    javamail模拟邮箱功能--邮件删除-中级实战篇【邮件标记方法】

                              写作不易,难免有疏漏和错误,还请慷慨指正,觉得有帮助帮忙推荐哦

      ps:欢迎转载,转载请注明出处:http://www.cnblogs.com/liuyitian/p/4051922.html


                                                 每天多学一点点     代码少敲一点点

      

  • 相关阅读:
    python 包与模块
    互斥锁与自旋锁
    TCP三次握手四次挥手
    缓存击穿、缓存穿透、缓存雪崩
    五种IO模型
    MySQL使用mysqldump进行数据备份
    golang数据库连接池参数设置
    golang代码文件目录组织、包目录组织学习笔记
    【转】如何用Vim提高开发效率
    emacs显示行号
  • 原文地址:https://www.cnblogs.com/liuyitian/p/4051922.html
Copyright © 2011-2022 走看看