Unrecognized SSL message/DEBUG POP3: authentication command failed

从问题开始

用SMTP发送邮件和POP3介绍邮件时分别遇到上述连个错误,本质原因是没有进行SSL加密配置。

直接看解决方法:
Unrecognized SSL message
DEBUG POP3: authentication command failed/ A secure connection is requiered(such as ssl)

源代码如下:

package mail;

import java.util.Date;
import java.util.Properties;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;


class MyAuthor extends Authenticator{
    private String username;
    private String password;
    public MyAuthor(String username,String password){
        this.username = username;
        this.password = password;
    }
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(username,password);
    }
}

public class JavaMail {
    public static void main(String[] a){
        //属性类(Properties)操作
        Properties props = new Properties(); //保存服务器的地址和发送协议及端口号
        props.put("mail.transport.protocol","smtp");//确定发送协议
        props.put("mail.smtp.host", "smtp.qq.com");//服务器地址
        props.put("mail.smtp.port", "25");//服务器发送邮件的端口号
        props.put("mail.smtp.auth", "true");//确定使用安全认证
        props.put("mail.smtp.ssl.enable", "true");//使用ssl加密

        //会话类(Session)操作
        String username = "40****@qq.com";
        String password = "************";//登录的授权码而非密码
        MyAuthor auth = new MyAuthor(username, password);//构造认证对象
        Session session = Session.getDefaultInstance(props,auth);//根据连接服务器的信息和认证对象来获取与服务器的会话
        session.setDebug(true);

        //消息类/多媒体消息类(Message/MimeMessage)操作
        Message message = new MimeMessage(session);//根据会话来构造信息
        try{
            message.setFrom(new InternetAddress(username));//设置该消息的发件人地址
            message.setRecipient(RecipientType.TO,new InternetAddress(username));//设置该消息的接收人地址
            message.setSentDate(new Date());
            message.setSubject("Helloworld");//设置消息主题
            String m = "Hello world!";
            message.setText(m);//设置消息发送的文本

            //传输类(Transport)操作  
            Transport.send(message);//传送消息
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

这是因为SMTP使用的端口号25是不使用SSL加密的,而上面又设置需要进行SSL加密,产生冲突。
解决方法
1.端口号25改成465,SMTP的465端口支持SSL加密

props.put("mail.smtp.port", "465");

2.将传输协议改成SMTPS(SMTP-over-SSL),端口号可以不用设置了,因为SMTPS使用的就是465端口号。

props.put("mail.transport.protocol","smtps");

关于SMTP/POP3/IMTP协议可参考:
http://blog.csdn.net/lake121/article/details/42099995
http://edm.ishang.net/faq/detail/the-imap-protocol.html

关于JavaMail的API内容可参考:
http://www.360doc.com/content/14/0306/17/16088576_358273704.shtml

关于JAF的作用可参考:
http://blog.csdn.net/kissqw/article/details/6555860

下面介绍一下关于JavaMail的其他内容

发送有附件的邮件

直接上代码:
MailBean类用于保存和邮件相关的信息。

package mail;

public class MailBean {
    private String username;
    private String password;
    private String sender;
    private String reciver;
    private String message;
    private String paths[];

    public MailBean(){//测试用的信息
        this.username = "******@qq.com";
        this.password = "***********";
        this.sender = "*****.com";
        this.reciver = "****.com";
        this.message = "test";
        this.paths = new String[2];
        paths[0] = "e:\\test10\\auto.html";//附件内容
        paths[1] = "e:\\2.bmp";
    }
    public MailBean(String username,String password,String sender,String reciver,String message,String paths[]){
        this.username = username;
        this.password = password;
        this.sender = sender;
        this.reciver = reciver;
        this.message = message;
        this.paths = paths;
    }
    public String getUsername() {
        return username;
    }
    public String getPassword() {
        return password;
    }
    public String getSender() {
        return sender;
    }
    public String getReciver() {
        return reciver;
    }
    public String getMessage() {
        return message;
    }
    public String[] getPaths() {
        return paths;
    }
}

MailService类提供处理邮件信息的方法,并发送邮件。

package mail;

import java.util.Date;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.DataSource;
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.MimeMessage.RecipientType;
import javax.mail.internet.MimeMultipart;
public class MailService {
    private Properties sendParameter;
    public Properties getsendParameter(){
        if (sendParameter==null) {
            sendParameter = new Properties();
            sendParameter.put("mail.transport.protocol","smtps");//确定发送协议
            sendParameter.put("mail.smtp.host", "smtp.qq.com");//服务器地址
            sendParameter.put("mail.smtp.auth", "true");//确定使用安全认证
            sendParameter.put("mail.smtp.ssl.enable", "true");//使用SSL加密
        }
        return sendParameter;
    }
    public void sendMail(MailBean bean){
        Properties props =this.getsendParameter(); //保存服务器的地址和发送协议及端口号

        String username = bean.getUsername();
        String password = bean.getPassword();//登录的授权码而非密码
        MyAuthor auth = new MyAuthor(username, password);//构造认证对象
        Session session = Session.getDefaultInstance(props,auth);//根据连接服务器的信息和认证对象来获取与服务器的会话
        session.setDebug(true);

        MimeMessage message = new MimeMessage(session);//根据会话来构造信息
        try{
            message.setFrom(new InternetAddress(bean.getSender()));//设置该消息的发件人地址
            message.setRecipient(RecipientType.TO,new InternetAddress(bean.getReciver()));//设置该消息的接收人地址
            Multipart filePart = new MimeMultipart();//构造带附件的消息体
            MimeBodyPart body = null;

            body = new MimeBodyPart(); //这个body用于显示正文内容
            body.setText(bean.getMessage());
            filePart.addBodyPart(body);
            for(int i=0;i<bean.getPaths().length;i++){
                body = new MimeBodyPart();
                DataSource source = new FileDataSource(bean.getPaths()[i]);//获取附件的路径
                DataHandler handle = new DataHandler(source);
                body.setDataHandler(handle);
                String filename = bean.getPaths()[i].substring(bean.getPaths()[i].lastIndexOf("\\")+1,bean.getPaths()[i].length());
                body.setFileName(filename);//设置附件名
                filePart.addBodyPart(body);
            }
            message.setContent(filePart);
            message.setSentDate(new Date());
            message.setSubject("Mutipart");//设置消息主题

            Transport.send(message);//传送消息  
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

SendServlet类用于获取用户提交的信息,并调用前面所编写的业务类完成邮件的发送。此处用MailBean默认的信息。需要在web.xml中进行注册,这里不赘述了。

package mail;

import java.io.IOException;
import java.rmi.ServerException;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/SendMail")
public class SendServlet extends HttpServlet{

    protected void doGet(HttpServletRequest request,HttpServletResponse response)throws ServerException,IOException {
        /*request.setCharacterEncoding("gbk");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String sender = request.getParameter("sender");
        String reciver = request.getParameter("reciver");
        String message = request.getParameter("message");
        String paths[] =request.getParameterValues("path");
        MailBean bean = new MailBean(username,password,sender,reciver,message,paths);*/
        //如果要借助浏览器来动态获得则使用以上内容,并且需要编写界面表单的参数如上
        MailBean bean = new MailBean();//测试时创建的默认信息
        MailService service = new MailService();
        service.sendMail(bean);
    }
}

收取并解析邮件

解析和显示邮件

解析和显示一封邮件就是把封装在Message对象中的数据解析出来,包括邮件头中的邮件发送者地址、邮件主体、发送时间,邮件正文中的文本信息、内嵌资源,邮件体中的附件信息等,然后把解析出来的这些信息交给数据显示软件显示。

JavaMail解析邮件的流程如下:

  1. 调用Message对象的getForm,getSubject等方法,可以得到邮件发送人和主题等信息,调用getContentType方法得到邮件的类型。
  2. 通过Message.getContentType方法的返回值判断邮件类型,并调用Message.getContent方法得到邮件内容。如果邮件类型为“text/plain”或”text/html”,表示邮件为纯文本,此时调用Message对象的getContent方法得到邮件内容,然后将返回对象的类型转换成String输出给显示软件即可。如果邮件类型为”multipart/*”,表示邮件内容是一个复合类型,此时需将Message.getContent方法返回的对象转换成Multipart。
  3. 调用Multipart对象的getCount方法检测Multipart对象中封装了多少个BodyPart对象,并通过for循环逐一取出Multipart对象中的每个BodyPart对象进行处理。
  4. 在处理每个BodyPart对象时,首先调用BodyPart对象的getContentType方法得到他的MIME类型,然后根据MIME类型做出如下三种情况的处理:
    • 当MIME类型表示的是图片、声音或附件等二进制数据时,此时应调用BodyPart对象的getDataHandler方法得到封装了数据的DataHandler对象,然后调用DataHandler对象的getInputStream方法获得与数据相关的InputStream对象,通过这个InputStream对象中即可获得原始的二进制数据内容。(也可以直接part.getInputStream)
      类似这样:
      Content-Type: application/octet-stream; name=2.bmp
      Content-Transfer-Encoding: base64
      Content-Disposition: attachment; filename=2.bmp
      Qk02DDAAAAAAADYAAAAoAAAAVgUAAAADAAABABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA......
    • 当MIME类型为”text/*”时,表示BodyPart对象中保存的是纯文本数据,此时调用BodyPart对象的getContent方法并将返回的对象转换成String输出给显示软键显示即可。
    • 当MIME类型是”multipart/mixed”时,表示BodyPart对象中保存的是一个复合MIME消息,此时调用BodyPart对象中的getContent方法得到封装复合MIME消息的对象并将它转换成Multipart类型。

这里实现了读取该账户中的邮件,将附件以文件形式保存,将文本内容显示出来。

@WebServlet("/MailReceives")
public class MailReceives extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public MailReceives() {
        super();
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("message/rfc822;charset=utf-8");
        PrintWriter out = response.getWriter();
        Properties props = System.getProperties();

        final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
        props.setProperty("mail.pop3.socketFactory.class", SSL_FACTORY);
        props.setProperty("mail.pop3.port", "995");//需要指明使用995端口,否则默认的110端口不支持SSL  
        String host = "pop.qq.com";//确定服务器地址
        String username = "******@qq.com";
        String password = "******";//授权码

        Session session = Session.getDefaultInstance(props);//获取与服务器 之间的会话连接
        Store store = null;
        Folder fold = null;
        try{
            store = session.getStore("pop3");//通过会话获取Store对象
            store.connect(host, username, password);//登录到指定服务器
            fold = store.getFolder("inbox");
            fold.open(Folder.READ_ONLY);//只读方式打开文件夹
            Message[] mess = fold.getMessages();//获取文件夹下面的邮件
            for(int i=0;i<mess.length;i++){//遍历每份邮件
                Message m = mess[i];
                String path = "e:\\mail\\"+m.getSubject();
                File folder = new File(path);//本地创建文件夹
                folder.mkdirs();

                Object content = m.getContent();// getContent() 是获取包裹内容
                if (content instanceof Part)  {  
                    Part body = (Part)content; 
                    rePart(body,path);
                }  
                else if (content instanceof Multipart)  {  
                    Multipart multipart = (Multipart) content ;  
                    reMultipart(multipart,path); 
                }
                else {  
                    System.out.println("类型" + m.getContentType());  
                    System.out.println("内容" + m.getContent());  
                }  
            }

        }catch (Exception e) {
            e.printStackTrace();
        }finally{
            try {
                if(fold!=null)
                    fold.close(false);//不删除邮件
                if(store!=null)
                    store.close();
            }catch (MessagingException e) {
                    e.printStackTrace();
            }
        }
    }
    //part是最小的单位,可以直接操作了
    private void rePart(Part part,String path)throws MessagingException,  
    UnsupportedEncodingException, IOException, FileNotFoundException{
        if(part.getDisposition()!=null&&part.getDisposition().equals(Part.ATTACHMENT)){
            //是附件形式存在的,可以直接提取出文件名,若part.getDisposition()是INLINE形式的(内嵌的)就按照文本方式输出而不保存成文件
            String strFileName = MimeUtility.encodeText(part.getFileName());
            System.out.println("附件名: " + strFileName);
            System.out.println("内容类型: " + MimeUtility.decodeText(part.getContentType()));  
            System.out.println("附件内容:" + part.getContent()); 
            InputStream in = part.getInputStream();// 打开附件的输入流  
            // 读取附件字节并存储到文件中  
            FileOutputStream out = new FileOutputStream(path+"\\"+strFileName);  
            int data;  
            while((data = in.read()) != -1) {  
                out.write(data);  
            }  
            in.close();  
            out.close();  
        }else {  
            if(part.getContentType().startsWith("text/plain")) {  
                System.out.println("文本内容:" + part.getContent());  
            } else {  
                System.out.println("HTML内容:" + part.getContent());  
            }  
        }  
    }
    //Multipart可以再分成Part或者Mutipart
    private void reMultipart(Multipart multipart,String path) throws Exception {  
        System.out.println("邮件"+path.split("\\\\")[2]+"此块共有" + multipart.getCount() + "部分组成");  
        // 依次处理各个部分  
        for (int j = 0, n = multipart.getCount(); j < n; j++) {  
            //System.out.println("处理第" + j + "部分");  
            Part part = multipart.getBodyPart(j);//解包, 取出 MultiPart的各个部分, 每部分可能是邮件内容,  
            // 也可能是另一个小包裹(MultipPart)  
            // 判断此包裹内容是不是一个小包裹, 一般这一部分是 正文 Content-Type: multipart/alternative  
            if (part.getContent() instanceof Multipart) {  
                Multipart p = (Multipart) part.getContent();// 转成小包裹  
                //递归迭代  
                reMultipart(p,path);  
            } else {  
                rePart(part,path);  
            }  
         }  
    }

原本报错:
DEBUG POP3: authentication command trace suppressed
DEBUG POP3: authentication command failed

解决方法:
加上下面几句(代码内已加上):

final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
props.setProperty("mail.pop3.socketFactory.class", SSL_FACTORY);
props.setProperty("mail.pop3.port", "995");
//需要指明使用995端口,否则默认的110端口不支持SSL
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值