web-dev-qa-db-ja.com

javax.mail APIを使用してバルクメールを効率的に送信する方法は? &再利用認証済みセッションを使用して速度を向上させることはできますか?

Javax.mailAPIを使用してメールを送信できます。ただし、ここでの問題は、メールごとに平均して宛先に送信するのに約4.3秒かかることです。

20通のメールを連続して送信する場合、約86.599秒かかります。私の要件では、このアプローチは機能しません。短時間で大量のメールを送信できるアプローチを探しています。

デバッグログを見ると、APIは送信するすべてのメッセージについてSMTPサーバーに対して認証を試みています。しかし、私はセッションを1回だけ作成し、送信するすべてのメールに同じセッションを使用しています。今私の質問は、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

これについてのあなたの考えを私に知らせてください、そしてこれに関するどんな助けも本当にありがたいです。

-ナレンドラ

17
Narendra

どのようにメッセージを送信していますか? JavaMail FAQ は、静的Transport.sendメソッドは、適切なTransportインスタンスを作成して接続し、sendMessageを呼び出してから接続を再度閉じる便利なメソッドであるため、メッセージごとに新しい接続を開きます。 Transportから独自のSessionインスタンスを取得した場合は、一度接続してから、sendMessageを繰り返し呼び出して、1つの接続で複数のメッセージを送信し、最後にclose それ。 (未テスト)の線に沿った何か:

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

私は仕事で同じ要件を得ました。一括メールとスタンドアロンメールを送信する必要があります。単純で満足のいく答えは見つかりません。一括メールは単一の接続を使用して送信できますが、スタンドアロンのメールは、メールをバッチで送信する非同期バッファリングを作成するまで送信できません。

大事なことを言い忘れましたが、短時間で多くのTransport接続を使用すると、すべてのポートがno more socket handles are available状態でスタックするため、TIME_WAITにつながる可能性があります。

私は最終的に、SMTP接続プールが最善であると結論付けました。ライブラリが存在しないため(少なくとも無料) 私は自分で作成します Apache CommonPoolと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("[email protected]");
    mimeMessageHelper.setFrom("[email protected]");
    mimeMessageHelper.setSubject("Hi!");
    mimeMessageHelper.setText("Hello World!", false);
    transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
}

//Close the pool, usually when the application shutdown
smtpConnectionPool.close();
11
Nicolas Labrot

標準のJavaメールAPIがあなたが達成しようとしていること(セッションの再利用)を許可するかどうかはわかりませんが、マルチスレッドの使用を検討することができます:

ThreadPoolを使用して、メール送信ジョブを送信します。次に、ThreadPoolによって非同期に実行されるジョブクラスコード内でエラー処理/再送信を実行すると、メインスレッドは他のことを再開できます。ジョブの送信には数ミリ秒しかかかりません。 Javaでスレッドプールを使って何かを実装してからしばらく経ちましたが、それはかなり簡単で簡単だったことを覚えています。あなたがグーグル「JavaThreadPool」なら、あなたはたくさんの資料を見つけます。

1
FelixD

非常に優れたパフォーマンスが得られるため、スレッドプールを使用できます。以下のコードスニペットを実装して共有しました。

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);
}
0
S Boot