提高发送Java邮件的速度

4

我已经用Java编写了一段代码,使用Java邮件发送邮件到smtp服务器。发件人和收件人的电子邮件地址以及邮件的主题和正文保存在数据库(SQL)中。然而,这种方式发送邮件非常缓慢。我需要发送批量邮件(大约每秒300封)。如何使用多线程提高发送邮件的速度?

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import oracle.jdbc.OraclePreparedStatement;

public class mainclass {

Properties emailProperties;
Session mailSession;
MimeMessage emailMessage;



public static void main(String args[]) throws AddressException,
        MessagingException {
            OraclePreparedStatement pst;
            Connection con;
            String userna;
            con = connectDB.connect();
            try {
                    Statement st = con.createStatement();
                    String sm = "SELECT * FROM EmailQueue WHERE sent = 'no'";
                    ResultSet res = st.executeQuery(sm);
                    while (res.next()) {
                        System.out.println(res.getString("from_email_address") + " " + res.getString("to_email_address"));
                        String id = res.getString("id");
                        String toEmails = res.getString("to_email_address");
                        String emailSubject = res.getString("subject");
                        String emailBody = res.getString("body");
                        String emailHost = "smtp.gmail.com";
                        String fromUser = res.getString("from_email_address");
                        String fromUserEmailPassword = res.getString("password");
                        mainclass javaEmail = new mainclass();
                        javaEmail.setMailServerProperties();
                        javaEmail.createEmailMessage(toEmails, emailSubject, emailBody);
                        javaEmail.sendEmail(emailHost, fromUser, fromUserEmailPassword);
                        Statement sn = con.createStatement();
                        String up = "Update EmailQueue set sent='yes' where id='"+id+"'";
                        sn.executeQuery(up);
                    }

        } catch(Exception e) {
            System.out.println("problem");
        }


}

public void setMailServerProperties() {

    String emailPort = "587";//gmail's smtp port

    emailProperties = System.getProperties();
    emailProperties.put("mail.smtp.port", emailPort);
    emailProperties.put("mail.smtp.auth", "true");
    emailProperties.put("mail.smtp.starttls.enable", "true");

}

public void createEmailMessage(String toEmails, String emailSubject, String emailBody) throws AddressException,
        MessagingException {

    mailSession = Session.getDefaultInstance(emailProperties, null);
    emailMessage = new MimeMessage(mailSession);

        emailMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(toEmails));


    emailMessage.setSubject(emailSubject);
    emailMessage.setContent(emailBody, "text/html");//for a html email
    //emailMessage.setText(emailBody);// for a text email

}

public void sendEmail(String emailHost, String fromUser, String fromUserEmailPassword) throws AddressException, MessagingException {


    Transport transport = mailSession.getTransport("smtp");

    transport.connect(emailHost, fromUser, fromUserEmailPassword);
    transport.sendMessage(emailMessage, emailMessage.getAllRecipients());
    transport.close();
    System.out.println("Email sent successfully.");
}

}

取决于瓶颈在哪里,但是您现有的主线程可以继续从数据库读取行,但将作业发送到线程池以创建执行sendMessage的mainclass实例。 - quamrana
谢谢Quamrana。我创建了一个线程池来发送邮件,而主线程继续从数据库中读取行。 - user3804428
@user3804428,我能看一下你如何使用线程提高速度吗? - gbubemi smith
2个回答

2
快速发送大量电子邮件的关键在于多线程 --既要在Java代码中使用多线程,也要在电子邮件服务器的配置中使用多线程。
当您通过JavaMail发送电子邮件时,实际上只是将一条消息提交到SMTP电子邮件服务器。然后,您的SMTP服务器查找接收域的MX地址(电子邮件地址中“@”后面的部分)以获取接收SMTP服务器的IP地址。然后它开始与接收SMTP服务器进行交谈,并最终导致消息被传输。由于各种原因,这个过程可能会非常缓慢。 - 查找接收服务器IP地址的过程可能需要时间 - 与接收SMTP服务器的对话可能非常缓慢,具体取决于其负载和策略。有些对话实际上可能需要几分钟的时间。
因此,为了加快电子邮件应用程序的吞吐量,您应该: 1)确保您的SMTP服务器本地具有缓存名称服务器。 这将使其识别接收SMTP的IP的过程更加快速。 基本上,缓存名称服务器在本地记住过去的查找请求,因此对于相同的域名的后续请求速度会更快(可能快100倍)。 换句话说,一旦您查找“gmail.com”的接收IP地址,直到其TTL过期之前,您就无需再次查找它。在Red Hat Linux上,您可以通过“yum install caching-nameserver”配置bind为缓存名称服务器。
2)将SMTP服务器配置为具有许多线程。由于大多数时间,您的SMTP服务器将等待其他服务器继续进行他们的“对话”,因此它可以高效地同时进行数百个会话。我使用Postfix,因为它快速可靠。默认情况下,Postfix配置为具有100个同时运行的SMTP进程。我将其提高到300或更多。在Postfix中,您可以使用default_process_limit设置配置此进程限制。
3)调整您的SMTP服务器,以考虑某些接收服务器可能非常慢或完全不响应。例如,默认情况下,Postfix配置为等待300秒(五分钟!)以使接收服务器对其最初的“HELO”做出响应。我将这个时间缩短了很多,将smtp_helo_timeout = 100s的配置选项设置为100秒。由于接收服务器很慢而未能成功发送的消息仅被您的SMTP服务器排队以稍后重试。
4)在您使用JavaMail时使用多线程。在我的Java代码中创建多线程,我已经将速度加快了几个数量级。这样,与我的SMTP服务器同时进行许多对话。

1
多线程发送邮件会给您的邮件服务器带来成千上万个请求,最终导致宕机。
当您发送电子邮件(例如使用JavaMail)时,只是将新邮件提交给您的邮件服务器。实际上是邮件服务器将邮件发送给收件人,您无法在Java端做任何事情来提高交付速度。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接