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

2022-09-02 09:22:58

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

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

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

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

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

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

-纳伦德拉


答案 1

您如何发送消息?JavaMail FAQ建议静态方法将为每个消息打开一个新的连接,因为它是一种方便的方法,可以创建一个合适的实例,连接它,调用然后再次关闭连接。如果您从 中获得自己的实例,则可以连接一次,然后重复调用以在一个连接上发送多条消息,最后进行连接。类似于(未经测试)的东西:Transport.sendTransportsendMessageTransportSessionsendMessageclose

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

更新为使用 try with resources block:

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

答案 2

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

最后但并非最不重要的一点是,在短时间内使用大量连接可能会导致,因为所有端口都卡在状态下。Transportno more socket handles are availableTIME_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();

推荐