JavaMail中Session.getDefaultInstance的应用( 2008-08-20 14:51:30| 分类: java 技术)

近日,我在修改bug的过程中,发现一特别的现象,在邮件发送功能上竟然出现了修改帐号和密码后再发送邮件就报帐号不匹配的问题.

   仔细的查核相关代码,发现原来的开发者其实功能相当简单,连最简单的mail格式查核都没做,并且执行邮件发送程序后只给个不痛不痒的提示,连发送成功,失败都不知道.虽然如此,现在轮到我负责,也只有改了.

Jsp端相当简单:

  <%
String[] receiver = {request.getParameter("receiver")};

    String mail_subject = "Itmanager Mail Test.";
    String mail_content = "Itmanager Mail Test";
    Session mailSession = MailUtil.getSession(RptTaskMailConfig.SMTPServer,true,RptTaskMailConfig.Sender,RptTaskMailConfig.EmailPwd);
        try
        {
            MailUtil.sendTextMessage(mailSession,RptTaskMailConfig.Sender,
                                    receiver,null,
                                     mail_subject,mail_content,
                            "GB2312",null);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    %>

   后台:

        /**
     * 获得指定SMTP服务器的的Session实例
     * @param host
     * @param isAuth
     * @param user
     * @param password
     * @return
     */
    public static Session getSession(String host, boolean isAuth, String user, String password) {
        Properties props = new Properties();
        props.put("mail.smtp.host", host);
        props.put("mail.smtp.auth", String.valueOf(isAuth));

        Session session;
        if (user != null && user.length() > 0) {
            Authentic authentic = new Authentic(user, password);
            session = Session.getDefaultInstance(props, authentic);
        } else {
            session = Session.getDefaultInstance(props, null);
        }

        return session;
    }

    /**
     * 发送text格式的邮件
     * @param session
     * @param from
     * @param to
     * @param cc
     * @param subject
     * @param content
     * @param attachfile
     */
    public static void sendTextMessage(Session session, String from, String[] to, String[] cc, String subject,
            String content, Vector<File> attachfile) throws MessagingException {
        sendMessage(session, from, to, cc, subject, content, MIMETYPE_Default_TEXT, attachfile);
    }

    /**
     * 发送邮件
     * @param session
     * @param from 发件人
     * @param to 收件人
     * @param cc 抄送人
     * @param subject 主题
     * @param content 内容
     * @param mimeType
     * @param attachfile 附件文件名列表
     */
    public static void sendMessage(Session session, String from, String[] to, String[] cc, String subject,
            String content, String mimeType, Vector<File> attachfile) throws MessagingException {

        // 较验发件人
        if (!isValidMailAddress(from)) {
            return;
        }

        try {
            Message message = new MimeMessage(session);
            InternetAddress sendFrom = new InternetAddress(from);
            message.setFrom(sendFrom);
            message.setHeader("X-Mailer", "ITManager Mailer");
            message.setHeader("From", "<" + from + ">");

            // 设置收件人
            InternetAddress[] sendTo = new InternetAddress[to.length];
            for (int i = 0; i < to.length; i++) {
                sendTo[i] = new InternetAddress(to[i]);
            }
            message.setRecipients(Message.RecipientType.TO, sendTo);

            // 设置抄送人
            if (cc != null) {
                InternetAddress[] copyTo = new InternetAddress[cc.length];
                for (int i = 0; i < cc.length; i++) {
                    copyTo[i] = new InternetAddress(cc[i]);
                }
                message.setRecipients(Message.RecipientType.CC, copyTo);
            }

            // 设置主题
            message.setSubject((subject == null || subject.length() == 0) ? "No subject" : MimeUtility
                    .encodeText(subject));

            // 设置正文
            MimeMultipart mp = new MimeMultipart();
            MimeBodyPart mbp = new MimeBodyPart();
            mbp.setContent(content, mimeType);
            mp.addBodyPart(mbp);

            // 添加附件
            if (attachfile != null) {
                Enumeration<File> efile = attachfile.elements();
                while (efile.hasMoreElements()) {
                    File ele = efile.nextElement();
                    mbp = new MimeBodyPart();
                    FileDataSource fds = new FileDataSource(ele);
                    mbp.setDataHandler(new DataHandler(fds));
                    sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
                    mbp.setFileName("=?GBK?B?" + enc.encode(fds.getName().getBytes()) + "?=");
                    // mbp.attachFile(ele);
                    mp.addBodyPart(mbp);
                }
            }
            message.setContent(mp);

            // 设置发送日期
            message.setSentDate(new Date());
            message.saveChanges();

            long start = System.currentTimeMillis();
            System.out.println("Start time:" + start);
            Transport.send(message);
            long end = System.currentTimeMillis();
            System.out.println("End time:" + end);
            System.out.println("Send time:" + (end - start) + "ms");
        } catch (IOException ioe) {
            ioe.printStackTrace();
        } catch (NoSuchProviderException nspe) {
            nspe.printStackTrace();
        } catch (MessagingException me) {
            throw me;
        }
    }

程 序的整个逻辑都比较清晰,调javax.mail包,直接使用天的Transport.send(message)发送邮件功能.但是却出现了当第一次进 入系统时,可以正常发送邮件,但是如果更改邮件用户名,密码等资料后再发送就报异常.初步判断是jsp页面传入资料时出错,进入debug状态进行调试, 发现 MailUtil.getSession(RptTaskMailConfig.SMTPServer,true,RptTaskMailConfig.Sender,RptTaskMailConfig.EmailPwd) 里的值是保存后新改的值.就陷入迷茫中,既然是新的值为什么会报帐号和密码不匹配.继续调试,估计是Session的问题,应该是第一次的session 没被清除,但是上网查了资料也没有说java邮件发送后需要特别清除session的,并且程序中每次都会调用MailUtil.getSession, 即会产生不同的session,似乎也不存在这个问题.最后发现在session建立时Session.getDefaultInstance(props, authentic);相当可疑.查了一下:

何谓getDefaultInstance?
从处理流程中可以看出,首先是从缓存中查找是否有properties存在
如果存在,则加载默认的properties
如果不存在才加载用户自己定义的properties,
所以当一个应用为每个用户独立创建properties的时候,还是应该调用getInstance,
除非你希望有一个默认的properties让用户使用

问 题找到了,因为它会首先去内存和系统文件中去找properties,所以不管我在页面改几次数据,其实在后台中生成session时都和系统启动时的一 样,所以在MailUtil.sendTextMessage(mailSession,RptTaskMailConfig.Sender,
receiver,null,mail_subject,mail_content,"GB2312",null);时session里的sender和传入的sender不一致,因此出错,修改Session.getDefaultInstance(props, authentic);为Session.getInstance(props, authentic);后,可以正确发送修改帐号,密码等资料后的邮件.OK

最后再补充一下,session.getdefaultinstance和getinstance的区别 :

 如果想要同时使用两个帐号发送javamail,比如使用[email protected]发送1#邮件,使用[email protected]发送2#邮件,这时候,你就需要同时创建两个java.mail.Session对象。但是如果你仍然使用Session.getDefaultInstance创建session对象的话,你会发现,第二个username:[email protected]创建的session永远都和第一个一样,这是为什么呢?因为,getDefaultInstance是真正单例模式,而且,里面的username和password属性是final型的,无法更改。所以,你会发现两封email都是由[email protected]发出来的。所以这个时候你要使用javax.mail.Session.getInstance()方法来创建session对象。

你可能感兴趣的:(JavaMail中Session.getDefaultInstance的应用( 2008-08-20 14:51:30| 分类: java 技术))