日期:2014-05-20  浏览次数:20842 次

用Javamail发送邮件时,在transport.connect时停住了,整个线程就死在这不往下执行了
这个问题不是经常出现,平均发几千封邮件会出现一次,就是在
transport.connect(server, username, password)时出现的;

后来将其dump出来,如下所示,我还是找不出具体的原因,请哪位大牛帮忙分析下,不胜感激!

名称: Thread-23279
状态: RUNNABLE
阻塞总数:0  等待总数: 0

堆栈追踪: 
java.net.SocketInputStream.socketRead0(Native Method)
java.net.SocketInputStream.read(SocketInputStream.java:129)
com.sun.mail.util.TraceInputStream.read(TraceInputStream.java:110)
java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
java.io.BufferedInputStream.read(BufferedInputStream.java:237)
   - 已锁定 java.io.BufferedInputStream@6a48eb
com.sun.mail.util.LineInputStream.readLine(LineInputStream.java:89)
com.sun.mail.smtp.SMTPTransport.readServerResponse(SMTPTransport.java:2188)
com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:1699)
com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1120)
   - 已锁定 com.sun.mail.smtp.SMTPTransport@f849dc
com.jmail.mail.SendMail.send(SendMail.java:88)
com.jmail.SendThread.run(SendThread.java:61)
java.lang.Thread.run(Thread.java:662)
------解决方案--------------------
transport.connect(server, username, password)

这一句有反复执行吗?
如果连接上了服务器,则不需要再执行这行了,再去connect已经连接上的服务,有可能会引发问题。这一句执行一次就好。当连接继开时再去重连。
------解决方案--------------------
嗯。。。
每一次开一个线程,这样可能会有前一个线程未关闭连接,后一个线程又重连的情况吧?

另外,每发一个弄个线程,发一个万,要弄一万个线程?用线程池也好过这种方式吧,而且connect也只需要连接一次,要那么多次connect,再close干嘛。
------解决方案--------------------
个人觉得也不一定要用这么多线程去做。循环发送不行吗?比如:


    MimeMessage msg = new MimeMessage(session);
   
    Transport t = session.getTransport("smtp");

    ...........

    t.connect();

    for (int i = 0; .....) {
t.sendMessage(msg, new Address[] { recipients[i] });
        Thread.sleep(100);//防止发的太多,sleep一小会。
    }

    t.close();

------解决方案--------------------
根本原因是什么,我也只是猜测。
有只能是楼主采用多线程的方式,connect造成的问题,javamail api, connect方法有这么一句:

It is an error to connect to an already connected service. 

另外网络、邮件服务器也都可能出现问题,就是我们用IE打开自己的邮箱,去发一封邮件,也可能出现发送失败的情况,更何况楼主一直不停的发。所以一次很顺的发送大批量邮件,中间出现问题也应该是正常情况(具体我也没测试过)。

不过刚才有一个帖子让我想起,发送的时候,可以一次发送多个人,就好像用邮箱发邮件时,也可以抄送一样。

Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("from@163.com"));
msg.setSubject("test javamail");
msg.setRecipients(RecipientType.TO, 
InternetAddress.parse("user1@163.com,user2@163.com,user3@163.com"));//可添加多个接收地址
Transport.send(msg);