同时发送带有附件和“打开的文件过多”错误的HtmlEmail

时间:2018-08-06 11:55:47

标签: java apache email

我怀疑我使用了错误的Apache Common Email库来发送带有附件的电子邮件。 有时会出现“打开的文件太多” 错误,如果我用 lsof 检查打开的文件,我会看到附件文件被多次打开:

image1.png image2.png image1.png ...

所以我怀疑我没有正确释放文件(或没有关闭某些资源)。该软件也可能正常运行,但是如果外部SMTP服务器失败(连接异常),我的代码将不会释放某些资源。

来源:

/* Async Thread to send email */
Thread t = new Thread(){
@Override
public void run(){
      try{
         task(request,idNewsletter);
      }
      catch (Exception e){
         log.error("Error " + e);
      }
}
};
t.start();
[...]

任务方法:

    ExecutorService executor = Executors.newFixedThreadPool(10);
    [...]

    List<Future<Integer>> list = new ArrayList<Future<Integer>>();
    for (int i = 0; i < dests.length; i++) {        
        HtmlEmail htmlEmail = getHtmlMail([...]);

        ArrayList<InternetAddress> dest = new ArrayList<InternetAddress>();
        InternetAddress add = new InternetAddress();
        add.setAddress(dests[i]);
        dest.add(add);

        htmlEmail.setBcc(dest);         
        htmlEmail.setMailSession(getEmailSession());            
        htmlEmail.buildMimeMessage();

        Callable<Integer> worker = new EmailService(htmlEmail,i);        
        Future<Integer> future = executor.submit(worker);            
        list.add(future);

    }

    try {
        executor.shutdown();
        executor.awaitTermination(28800, TimeUnit.SECONDS);
    }
    catch (InterruptedException e) {
       log.error("Error=" + e);
    }
    finally {
        if (!executor.isTerminated()) {
            log.error("Task cancelled");
        }
        executor.shutdownNow();
    }

getHtmlEmail方法

private static URL image;
static {
     image= (new File("somepath").toURI().toURL());
 }


private HtmlEmail getHtmlMail([...]){

      HtmlEmail htmlEmail = new HtmlEmail();

        htmlEmail.setCharset("UTF-8");
        htmlEmail.setSubject("someSubject");
        htmlEmail.setFrom(from);
        htmlEmail.setSentDate(new java.util.Date());
        [...]
        String cidImage= htmlEmail.embed(image, "Email image");
        text= text.replace("cid:image", "cid:" + cidImage);

        [...] /* Other attachments */

        htmlEmail.setHtmlMsg(text); 
        return htmlEmail;

}

getEmailSession方法

private Session getEmailSession() throws Exception{  
        if (mailSession != null)
            return mailSession;
        else {
            InitialContext ic = new InitialContext();
            mailSession = (Session) ic.lookup("someJNDI");

            mailSession.getProperties().put("mail.smtp.connectiontimeout", 1000);
            mailSession.getProperties().put("mail.smtp.timeout", 5000);

            return mailSession;
        }

   }

以及发送电子邮件的方法

@Override
public Integer call() throws Exception {    
    try{                                                        
           htmlEmail.sendMimeMessage();    
       }
    catch(Exception e){  
           log.error("Error=" + e);
           htmlEmail=null;
           return new Integer(0);
       }                         
      return new Integer(1);
}  

有任何提示吗?

预先感谢 安德里亚

2 个答案:

答案 0 :(得分:1)

我相信这是问题所在

static {
     image= (new File("somepath").toURI().toURL());
 }

它是static。这是您遇到的并发问题。 它总是在那里。 我认为这是正在发生的事情。假设这在名为Url的类中,并且您有一个非静态的getUrl()返回此值。 如果您这样做:

Url url1 = new Url();
Url url2 = new Url();
url1.getUrl();
url2.getUrl();

然后,它们各自应返回不同的url实例。但是,您正在将url属性初始化为static,所以实际上发生的是 所有Url实例都只有一个url。 url属性不属于每个对象,而仅属于类本身。 因此,当您尝试调用它时,他们都试图一次又一次地访问该文件,因为首先它从未被“创建”或初始化过每个实例。认为它是永远存在的东西,因为类本身拥有它,而不是实例,因此给您带来Too many open files错误。

因此,我建议您将其从静态中删除。也许您可以执行以下操作:

class Url{
    private final URL url;
    public Url() {
        url= (new File("somepath").toURI().toURL());
    }
}

然后只需在任意位置使用该url属性。

答案 1 :(得分:0)

更新:即使我将字段重写为非静态字段,问题仍然存在。 我想这个版本的库(Apache Common Email 1.5)有问题(错误?)