Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apache Commons Email and Reusing SMTP Connections

Currently I am using Commons Email to send email messages, but I have not been able to find a way to share smtp connections between emails sent. I have code like the following:

    Email email = new SimpleEmail();
    email.setFrom("[email protected]");
    email.addTo("[email protected]");
    email.setSubject("Hello Example");
    email.setMsg("Hello Example");
    email.setSmtpPort(25);
    email.setHostName("localhost");
    email.send();

Which is very readable, but is slow when I do a large amount of messages, which I believe is the overhead of reconnecting for each message. So I profiled it with the following code and have found that using the reusing the Transport makes things about three times faster.

    Properties props = new Properties();
    props.setProperty("mail.transport.protocol", "smtp");
    Session mailSession = Session.getDefaultInstance(props, null);
    Transport transport = mailSession.getTransport("smtp");
    transport.connect("localhost", 25, null, null);

    MimeMessage message = new MimeMessage(mailSession);
    message.setFrom(new InternetAddress("[email protected]"));
    message.addRecipient(Message.RecipientType.TO, new InternetAddress("[email protected]"));
    message.setSubject("Hello Example");
    message.setContent("Hello Example", "text/html; charset=ISO-8859-1");

    transport.sendMessage(message, message.getAllRecipients());

So I was wondering if there was a way to make Commons Email reuse an SMTP connection for multiple email sendings? I like the Commons Email API better, but the performance is kind of painful.

Thanks, Ransom

like image 544
Ransom Briggs Avatar asked Jul 14 '11 14:07

Ransom Briggs


Video Answer


2 Answers

I came up with the following solution after digging into the commons source itself. This should work, but there may be better solutions I do not know of

    Properties props = new Properties();
    props.setProperty("mail.transport.protocol", "smtp");
    Session mailSession = Session.getDefaultInstance(props, null);
    Transport transport = mailSession.getTransport("smtp");
    transport.connect("localhost", 25, null, null);

    Email email = new SimpleEmail();
    email.setFrom("[email protected]");
    email.addTo("[email protected]");
    email.setSubject("Hello Example");
    email.setMsg("Hello Example");
    email.setHostName("localhost"); // buildMimeMessage call below freaks out without this

    // dug into the internals of commons email
    // basically send() is buildMimeMessage() + Transport.send(message)
    // so rather than using Transport, reuse the one that I already have
    email.buildMimeMessage();
    Message m = email.getMimeMessage();
    transport.sendMessage(m, m.getAllRecipients());
like image 60
Ransom Briggs Avatar answered Oct 22 '22 17:10

Ransom Briggs


Could we not achieve this easier by getting the mail session from the first email using getMailSession() and putting it to all subsequent messages using setMailSession() ?

Not 100% sure what the

Please note that passing a username and password (in the case of mail authentication) will create a new mail session with a DefaultAuthenticator. This is a convience but might come unexpected. If mail authentication is used but NO username and password is supplied the implementation assumes that you have set a authenticator and will use the existing mail session (as expected).

from the javadoc means, though :-/ http://commons.apache.org/email/api-release/org/apache/commons/mail/Email.html#setMailSession%28javax.mail.Session%29

see also: https://issues.apache.org/jira/browse/EMAIL-96

not sure how to continue here...

like image 36
cheesus Avatar answered Oct 22 '22 18:10

cheesus