如何有效地使用javax.mail API发送批量邮件? 我们可以使用重用经过身份validation的会话来提高速度吗?

我可以使用javax.mail API发送邮件。 但这里的问题是平均每封邮件需要大约4.3秒才能发送到目的地。

如果我按顺序发送20封邮件,则需要大约86.599秒。 根据我的要求,这种方法不起作用。 我正在寻找一种可以在更短的时间内发送大量邮件的方法。

当我查看调试日志时,API正在尝试向SMTP服务器validation它发送的每条消息。 但我只创建了一次会话,并为我发送的所有邮件使用相同的会话。 现在我的问题是,每次向smtp服务器validation自身时,这不是一个开销过程。 有没有更好的方法?

以下是您可能会发现有用的日志跟踪。

250-AUTH LOGIN PLAIN XOAUTH XOAUTH2 250 ENHANCEDSTATUSCODES DEBUG SMTP: Found extension "SIZE", arg "35882577" DEBUG SMTP: Found extension "8BITMIME", arg "" DEBUG SMTP: Found extension "AUTH", arg "LOGIN PLAIN XOAUTH XOAUTH2" DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg "" DEBUG SMTP: Attempt to authenticate DEBUG SMTP: check mechanisms: LOGIN PLAIN DIGEST-MD5 NTLM DEBUG SMTP: AUTH LOGIN command trace suppressed DEBUG SMTP: AUTH LOGIN succeeded 

请让我知道您对此的看法,对此的任何帮助都非常感谢。

-Narendra

你是如何发送消息的? JavaMail FAQ建议静态Transport.send方法将为每条消息打开一个新连接,因为它是一种方便的方法,可以创建合适的Transport实例,连接它,调用sendMessage ,然后再次关闭连接。 如果从Session获得自己的Transport实例,则可以连接一次,然后重复调用sendMessage以在一个连接上发送多条消息,最后将其close 。 某些事情(未经测试):

 Transport t = session.getTransport(); t.connect(); try { for(Message m : messages) { m.saveChanges(); t.sendMessage(m, m.getAllRecipients()); } } finally { t.close(); } 

我在工作中得到了同样的要求。 我必须发送批量电子邮件和独立电子邮件。 我没有找到简单而令人满意的答案:批量电子邮件可以使用单个连接发送,但是直到我创建异步缓冲才能批量发送电子邮件。

最后但并非最不重要的是,在短时间内使用大量Transport连接可能导致no more socket handles are available因为所有端口都处于TIME_WAIT状态。

我最后总结出最好的将是一个SMTP连接池,因为没有库(至少是免费的) 我使用Apache Common Pool和Java Mail 创建了我的库:

 //Declare the factory and the connection pool, usually at the application startup SmtpConnectionPool smtpConnectionPool = new SmtpConnectionPool(SmtpConnectionFactoryBuilder.newSmtpBuilder().build()); //borrow an object in a try-with-resource statement or call `close` by yourself try (ClosableSmtpConnection transport = smtpConnectionPool.borrowObject()) { MimeMessage mimeMessage = new MimeMessage(session); MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, false); mimeMessageHelper.addTo("to@example.com"); mimeMessageHelper.setFrom("from@example.com"); mimeMessageHelper.setSubject("Hi!"); mimeMessageHelper.setText("Hello World!", false); transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients()); } //Close the pool, usually when the application shutdown smtpConnectionPool.close(); 

不知道标准Java邮件API是否允许您尝试完成的任务(会话重用),但您可以考虑使用multithreading:

我会使用ThreadPool并向其提交邮件发送作业。 然后在作业类代码中进行任何error handling/重新发送,这是由ThreadPool异步执行的,并且您的主线程可以继续执行其他操作。 提交作业只需要几毫秒。 我用Java中的线程池实现了一段时间,但我记得它相当容易和直接。 如果您使用谷歌“Java ThreadPool”,您会发现很多材料。

您可以使用线程池,因为它提供了非常好的性能。我已经实现并分享了下面的代码片段。

 try { ExecutorService executor = Executors.newFixedThreadPool("no. of threads"); // no. of threads is depend on your cpu/memory usage it's better to test with diff. no. of threads. Runnable worker = new MyRunnable(message); // message is the javax.mail.Message executor.execute(worker); executor.shutdown(); executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS); }