3

I am using JavaMailSenderImpl from spring to send emails in my web application. I have created only one instance of this (Actually it is used by another object which is created using spring beans and is a singleton).

So the question is, Is JavaMailSenderImpl thread-safe? In my app, when multiple threads are using the mailSender simultaneously, will it lead to any race conditions?

kiran
  • 396
  • 3
  • 11
  • Yes it is thread safe once constructed. – M. Deinum Jun 13 '16 at 06:14
  • @M.Deinum I thought the same looking at the source code but am not sure. could you please elaborate and add an answer so that I can accept it. It will be great if you explain on how multiple threads can send mails at the same time. – kiran Jun 13 '16 at 06:24

3 Answers3

9

Yes the JavaMailSenderImpl is thread safe once it is constructed.

Take a look at the doSend method which does the actual work. It contains only method local variables (so each calling thread/stack has its own instance). (The same applies to the send method which add some functionality).

The methods like getSession are synchronized so only a single thread can have access to that method.

The biggest thing that makes it thread safe is the fact that there is (almost) no mutable shared state and the single mutable shared state (the Session) that there is is synchronized.

Next to that have been using it for over 12 years in production systems in a singleton fashion and never had any issues with concurrency. And yes we used it in highly concurrent applications. (And it is also the way other framework components like Spring Batch and Spring Integration use the JavaMailSender API).

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
  • But take a look at the order of [field loading](https://github.com/spring-projects/spring-framework/blob/master/spring-context-support/src/main/java/org/springframework/mail/javamail/JavaMailSenderImpl.java#L491). Username and password are loaded before `getSession` call, so there is no happens-before edge here even if some sync point after construction exists. – SerCe Jun 13 '16 at 09:05
  • Correct... But that is something you shouldn't do in the first place... And I state it is safe to use AFTER construction... Spring bootstraps in a single thread. Also `getUsername` and `getPassword` are called once, and after that used locally not globally. The same applies to other classes of the framework (which all contain a note: ** An instance of this class is thread-safe once configured.**.). – M. Deinum Jun 13 '16 at 09:38
  • @m-deinum, But `connectTransport` can be invoked multiple times from different threads (every `doSend`). So, if that thread started before spring-bootstrap thread, it can read null from `getUsername` because of the absence of the happens-before edge. (I agree with you that it is very impractical case, especially for x86, but I can't see any JMM proof of correctness here) – SerCe Jun 13 '16 at 10:09
  • So what... The transport isn't cached, it is recreated each time that is called. The thread that does that will probably get an exception that it cannot send an email. The transport is recreated for each call to `doSend`. – M. Deinum Jun 13 '16 at 10:15
  • Next to that you cannot get an instance of the bean before spring initialized it, unless you are creating new instances yourself. So Spring already has to be bootstrapped before you can even access an instance. And an object that references the bean is guaranteed to get an initialized bean. So unless you are messing around with usernames and passwords after that, using it in the normal way from a spring context makes it basically thread safe. – M. Deinum Jun 13 '16 at 10:21
  • That is true. You can access the object only after the spring has initialized it. Once I have the object, I am not messing with. I am only using it to send emails. I think that will solve my problem. Thanks!! – kiran Jun 13 '16 at 11:42
  • Bit late but I have a related question here: https://stackoverflow.com/questions/76496124/using-javamailsenderimpl-from-multiple-threads-and-having-reconnection-mechanism – Wrapper Jun 17 '23 at 13:46
0

It’s threadsafe but it’s worth adding that it can only support limited number of concurrent calls. I get the following error when my 4th thread calls sendMail function:

org.springframework.mail.MailSendException: Failed messages: com.sun.mail.smtp.SMTPSendFailedException: 432 4.3.2 STOREDRV.ClientSubmit; sender thread limit exceeded [Hostname=***]. So you should catch runtime exceptions and log it or else it just gets swallowed in the executor service running that thread.  

saurabh.in
  • 389
  • 3
  • 13
-1

No, it is not.

Although it has some synchronization in its source code, fields like user, passwords have no sync access. So, if you call setUsername in one thread there are no visibility guarantee for other threads.

SerCe
  • 5,826
  • 2
  • 32
  • 53
  • I am creating the object only once using spring and setting all the required fields for mail-server authentication and javaMailProperties. I am not changing those again. Once the object is created, multiple threads (jetty) use it send mails in parallel. Will it be an issue? I am specifically asking about the mail sending part. – kiran Jun 12 '16 at 18:16
  • [Here](https://github.com/spring-projects/spring-framework/blob/master/spring-context-support/src/main/java/org/springframework/mail/javamail/JavaMailSenderImpl.java#sourcegraph&def=JavaArtifact/org.springframework/spring-context-support/-/org/springframework/mail/javamail/JavaMailSenderImpl:type/getSession&L151-156), getters are called before first sync point, so according to happens-before it isn't thread safe, – SerCe Jun 12 '16 at 18:41