Production mail had been working for days on Mail Extension 1.1.0.7. On 2026-09-14 at about 09:17, with no deploy, no restart and no admin change, every cfmail call started failing with:
java.util.ServiceConfigurationError: jakarta.mail.Provider: com.sun.mail.imap.IMAPProvider not a subtype
It affected every cfmail call, from request threads and from cfthread alike.
STACK TRACE (top)
at java.base/java.util.ServiceLoader.fail(Unknown Source)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(Unknown Source)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(Unknown Source)
at java.base/java.util.ServiceLoader$2.hasNext(Unknown Source)
at java.base/java.util.ServiceLoader$3.hasNext(Unknown Source)
at jakarta.mail.Session.loadProviders(Session.java:964)
at jakarta.mail.Session.(Session.java:254)
at jakarta.mail.Session.getInstance(Session.java:281)
at org.lucee.extension.mail.smtp.SMTPConnectionPool.createSession(SMTPConnectionPool.java:148)
at org.lucee.extension.mail.smtp.SMTPConnectionPool$SessionAndTransport.(SMTPConnectionPool.java:175)
at org.lucee.extension.mail.smtp.SMTPConnectionPool.getSessionAndTransport(SMTPConnectionPool.java:57)
at org.lucee.extension.mail.smtp.SMTPClient.createMimeMessage(SMTPClient.java:492)
at org.lucee.extension.mail.smtp.SMTPClient._send(SMTPClient.java:909)
at org.lucee.extension.mail.smtp.SMTPClient.send(SMTPClient.java:798)
at org.lucee.extension.mail.tag.Mail.doEndTag(Mail.java:651)
WHAT WE FOUND
Three copies of the jakarta.mail classes are visible to the server:
- lucee-server/mvn/com/sun/mail/jakarta.mail/2.0.2/jakarta.mail-2.0.2.jar
(direct dependency of mail-1.1.0.7 / 1.1.0.8-RC) - lucee-server/mvn/com/sun/mail/jakarta.mail/2.0.1/jakarta.mail-2.0.1.jar
(pulled in transitively by org.apache.commons:commons-email2-jakarta:2.0.0-M1) - lucee-server/context/lib/jakarta.jakartaee-api-10.0.0.jar
(contains the jakarta.mail and jakarta.activation API packages)
The Session.java line numbers in the trace (964, 254, 281) match the com.sun jakarta.mail 2.0.x jars, not the EE 10 API jar. From a request thread:
- createObject(“java”, “jakarta.mail.Session”) and “jakarta.mail.Provider” resolve to context/lib/jakarta.jakartaee-api-10.0.0.jar (PhysicalClassLoader)
- the thread context class loader resolves com.sun.mail.imap.IMAPProvider to mvn/…/jakarta.mail-2.0.2.jar (a different PhysicalClassLoader)
So Session and Provider come from one class loader, and the IMAP provider found by ServiceLoader comes from another. Which copy wins seems to depend on load order. A development server with the same files, same versions and same extension works fine.
WHAT WE TRIED
- Service restart: still failing
- Moving mvn/…/jakarta.mail/2.0.1 out: Lucee downloaded it again at startup
- Upgrading Mail Extension to 1.1.0.8-RC plus restart: still failing
- Replacing jakarta.mail-2.0.1.jar with an empty (manifest-only) jar, keeping the .pom so it is not downloaded again, plus restart: cfmail worked
- About 6 minutes later Lucee logged a spontaneous config reload (“Init factory” / “Loaded config” in application.log, no admin action). Within minutes cfmail failed again with the same error, with the empty 2.0.1 jar still in place.
WORKAROUND
- Code: we added an HTTP API fallback for our most important sends.
- Planned: remove the jakarta/mail and jakarta/activation packages from context/lib/jakarta.jakartaee-api-10.0.0.jar, so only the Mail extension’s own jakarta.mail 2.0.2 is visible.
SUGGESTED FIX
- The Mail extension should not resolve two jakarta.mail versions: exclude com.sun.mail:jakarta.mail from commons-email2-jakarta, or align it on one version.
- The extension’s mail classes (Session, Provider and the providers found through ServiceLoader) should load from the extension’s own class loader, so other copies on the server (such as a Jakarta EE API jar in context/lib) cannot mix in.
- The error should not appear suddenly after days of working, or after a config reload.
Follow-up (2026-09-15):
We removed every other copy of the jakarta.mail classes and it still fails:
- jakarta.mail-2.0.1.jar in lucee-server/mvn replaced with an empty jar (manifest only)
- jakarta/mail and jakarta/activation packages removed from context/lib/jakarta.jakartaee-api-10.0.0.jar
- felix-cache cleared, full service restart
After the restart, every cfmail still fails with:
java.util.ServiceConfigurationError: jakarta.mail.Provider: com.sun.mail.imap.IMAPProvider not a subtype
Class lookups from a CFML request after the restart:
- createObject(“java”, “jakarta.mail.Session”) and “jakarta.mail.Provider”: not found (so no other copy is visible any more)
- thread context loader (EnvClassLoader) loadClass(“com.sun.mail.imap.IMAPProvider”):
file:/C:/lucee/tomcat/lucee-server/mvn/com/sun/mail/jakarta.mail/2.0.2/jakarta.mail-2.0.2.jar
loader = lucee.commons.lang.PhysicalClassLoader@1835dd38 - getResources(“META-INF/services/jakarta.mail.Provider”) through the thread context loader: none
jakarta.mail-2.0.2.jar is now the only jar on the server that contains jakarta.mail.Provider, and the error still happens. So it looks like the same jar is loaded by two different class loaders: the Mail extension’s Session/Provider come from one PhysicalClassLoader, and ServiceLoader resolves IMAPProvider through the thread context class loader (EnvClassLoader), which returns the class from another PhysicalClassLoader instance of the same jar.
The same install worked for days before this. It fails consistently now, across restarts. A possible fix: set the thread context class loader to the extension’s own class loader around Session.getInstance in SMTPConnectionPool.createSession.