I've met an error trying to send an email from ForkJoinPool
common pool (CompletableFuture.runAsync()
, ForkJoinPool.commonPool().execute()
, ...).
The error I can reproduce is Provider for jakarta.activation.spi.MailcapRegistryProvider cannot be found
but I also met a Not provider of jakarta.mail.util.StreamProvider was found
.
- It emerges only from packaged jar (including container env built with
bootBuildImage
). Running an app directly from IDE cause no error. - Changing JDK had no effect (tested with Temurin 17 JDK, Liberica 17 JDK and JRE).
- Sending email from Kotlin coroutine thread pool cause no error.
- Sending email from newly created pool cause no error (tested with
Executors.newFixedThreadPool(8)
).
I've made reference project freshly created by Spring initializr: https://github.com/turboezh/mail-test. Spring Boot version is 3.0.6.
Comment From: scottfrederick
Thanks for the report and the sample. I've been able to reproduce the Not provider of jakarta.mail.util.StreamProvider was found
error.
This is the full stack trace when the error occurs:
java.lang.IllegalStateException: Not provider of jakarta.mail.util.StreamProvider was found
at jakarta.mail.util.FactoryFinder.find(FactoryFinder.java:64)
at jakarta.mail.util.StreamProvider.provider(StreamProvider.java:177)
at jakarta.mail.Session.<init>(Session.java:254)
at jakarta.mail.Session.getInstance(Session.java:323)
at org.springframework.mail.javamail.JavaMailSenderImpl.getSession(JavaMailSenderImpl.java:163)
at org.springframework.mail.javamail.JavaMailSenderImpl.createMimeMessage(JavaMailSenderImpl.java:341)
at abc.email.test.EmailSender.sendSimple(EmailSender.java:33)
at abc.email.test.EmailSender.lambda$test$0(EmailSender.java:59)
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1804)
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1796)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Spring Boot auto-configures a org.springframework.mail.javamail.JavaMailSenderImpl
, but Boot is not in the code path when messages are sent as JavaMailSenderImpl
is part of Spring Framework. Since jakarta.mail
APIs are involved, the root cause may be out of the Spring Framework team's control also, but we'll need to transfer the issue so the Framework team can take a look.
I thought this might be a case of thread safety when the CompletableFuture
invocation and the After async
invocation run at the same time, but that does not appear to be the case. If the Before async
and After async
invocations are removed from the sample and a Thread.sleep(10000)
is added after the CompletableFuture.runAsync
returns, the error still happens.
Comment From: ztomic
It could be problem with class loader of ForkJoinPool
, something like in https://github.com/spring-projects/spring-boot/issues/19427
Comment From: turboezh
It could be problem with class loader of ForkJoinPool
Yes, it seems it is the case.
Adding
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
before mail sending leads to Not provider of jakarta.mail.util.StreamProvider was found
.
P.S.: Now I see tons of Classloader issue with CompletableFuture
problems. It seems this makes the default CompletableFuture pool a bit useless. :smiling_face_with_tear:
Comment From: turboezh
Another news: I don't know why, but after changing dependency to com.sun.mail:jakarta.mail:2.0.1
it all works fine without errors.
org.eclipse.angus:jakarta.mail:2.0.1
and 1.0.0
fails.
Comment From: evaldasu
Another news: I don't know why, but after changing dependency to
com.sun.mail:jakarta.mail:2.0.1
it all works fine without errors.org.eclipse.angus:jakarta.mail:2.0.1
and1.0.0
fails.
It is because com.sun.mail:jakarta.mail:2.0.1
doesn't have this.streamProvider = StreamProvider.provider();
in it's private Session
constructor as opposed to org.eclipse.angus:jakarta.mail
.
And the error Not provider of jakarta.mail.util.StreamProvider was found
comes from StreamProvider.provider()
Comment From: dipsk2
Is there a fix or a workaround that someone found for this issue? We are facing the same.
Comment From: turboezh
@dipsk2, this one works for me:
dependencies {
implementation("org.springframework.boot:spring-boot-starter-mail") {
exclude("org.eclipse.angus", "jakarta.mail")
implementation("com.sun.mail:jakarta.mail:2.0.1")
}
}
I think a latest version will work too.
Comment From: bclozel
Closing this issue as this is indeed independent of Spring Framework as explained in this comment.
Comment From: jmehrens
JakartaMail PR 701 should fix this issue:
https://github.com/jakartaee/mail-api/pull/701