diff --git a/api/src/main/java/jakarta/mail/Provider.java b/api/src/main/java/jakarta/mail/Provider.java
index 5d3caaf2..e6140fd8 100644
--- a/api/src/main/java/jakarta/mail/Provider.java
+++ b/api/src/main/java/jakarta/mail/Provider.java
@@ -22,7 +22,8 @@
* configuring providers using the Java SE
* {@link java.util.ServiceLoader ServiceLoader} mechanism.
* As an alternative the values could come from the
- * javamail.providers and javamail.default.providers
+ * javamail.providers, javamail.default.providers,
+ * jakarta.providers and jakarta.default.providers
* resource files. An application may also create and
* register a Provider object to dynamically add support
* for a new provider.
diff --git a/api/src/main/java/jakarta/mail/Session.java b/api/src/main/java/jakarta/mail/Session.java
index 5340b1eb..0e446d23 100644
--- a/api/src/main/java/jakarta/mail/Session.java
+++ b/api/src/main/java/jakarta/mail/Session.java
@@ -55,15 +55,33 @@
* implement the Store, Transport, and related
* classes. The protocol providers are configured using the following files:
*
+ * -
java.home/conf/javamail.X (deprecated)
+ * -
META-INF/javamail.X (deprecated)
+ * -
META-INF/javamail.default.X (deprecated)
* -
java.home/conf/jakarta.X
* -
META-INF/jakarta.X
* -
META-INF/jakarta.default.X
@@ -79,7 +97,8 @@
* java.home property points. The second method allows an
* application that uses the Jakarta Mail APIs to include their own resource
* files in their application's or jar file's META-INF
- * directory. The jakarta.default.X default files
+ * directory. The javamail.default.X (deprecated) and
+ * jakarta.default.X default files
* are part of the Jakarta Mail mail.jar file and should not be
* supplied by users.
*
@@ -96,6 +115,8 @@
* do not override, the default files included with the Jakarta Mail APIs.
* This means that all entries in all files loaded will be available.
*
+ * javamail.providers (deprecated),
+ * javamail.default.providers (deprecated),
* jakarta.providers and
* jakarta.default.providers
*
@@ -168,18 +189,20 @@
*
*
*
+ * javamail.address.map (deprecated),
+ * javamail.default.address.map (deprecated),
* jakarta.address.map and
* jakarta.default.address.map
*
* These resource files map transport address types to the transport
* protocol. The getType method of
* jakarta.mail.Address returns the address type. The
- * jakarta.address.map file maps the transport type to the
- * protocol. The file format is a series of name-value pairs. Each key
- * name should correspond to an address type that is currently installed
- * on the system; there should also be an entry for each
- * jakarta.mail.Address implementation that is present if it is
- * to be used. For example, the
+ * javamail.address.map (deprecated) and jakarta.address.map
+ * files map the transport type to the protocol. The file format is a series
+ * of name-value pairs. Each key name should correspond to an address type
+ * that is currently installed on the system; there should also be an entry
+ * for each jakarta.mail.Address implementation that is present
+ * if it is to be used. For example, the
* jakarta.mail.internet.InternetAddress method
* getType returns "rfc822". Each referenced protocol should
* be installed on the system. For the case of news, below,
@@ -202,11 +225,12 @@ public final class Session {
// Support legacy @DefaultProvider
private static final String DEFAULT_PROVIDER = "org.eclipse.angus.mail.util.DefaultProvider";
- // This is for backwards compatibility. Eventually we have to remove the second value of the next arrays.
- private static final String[] DEFAULT_ADDRESS_MAP_RESOURCES = new String[] {"/META-INF/jakarta.default.address.map", "/META-INF/javamail.default.address.map"};
- private static final String[] ADDRESS_MAP_RESOURCES = new String[] {"META-INF/jakarta.address.map", "META-INF/javamail.address.map"};
- private static final String[] DEFAULT_PROVIDER_RESOURCES = new String[] {"/META-INF/jakarta.default.providers", "/META-INF/javamail.default.providers"};
- private static final String[] PROVIDER_RESOURCES = new String[] {"META-INF/jakarta.providers", "META-INF/javamail.providers"};
+ // This is for backwards compatibility. javamail has more precedence than jakarta to not break compatibility
+ // Eventually we have to remove the first value of the next arrays.
+ private static final String[] DEFAULT_ADDRESS_MAP_RESOURCES = new String[] {"/META-INF/javamail.default.address.map", "/META-INF/jakarta.default.address.map"};
+ private static final String[] ADDRESS_MAP_RESOURCES = new String[] {"META-INF/javamail.address.map", "META-INF/jakarta.address.map"};
+ private static final String[] DEFAULT_PROVIDER_RESOURCES = new String[] {"/META-INF/javamail.default.providers", "/META-INF/jakarta.default.providers"};
+ private static final String[] PROVIDER_RESOURCES = new String[] {"META-INF/javamail.providers", "META-INF/jakarta.providers"};
private final StreamProvider streamProvider;
private final Properties props;
@@ -466,9 +490,16 @@ public synchronized PrintStream getDebugOut() {
}
/**
- * This method returns an array of all the implementations installed
- * via the jakarta.[default.]providers files that can
- * be loaded using the ClassLoader available to this application.
+ * This method returns an array of all the provider implementations installed
+ * via the javamail.[default.]providers (deprecated) and
+ * jakarta.[default.]providers files that can
+ * be loaded using the ClassLoader available to this application.
+ *
+ * For backwards compatibility, providers defined in
+ * javamail.* files take precedence over equivalent
+ * jakarta.* entries when conflicts occur. Applications are
+ * encouraged to migrate to the jakarta.* resource files, as
+ * support for javamail.* will be removed in a future release.
*
* @return Array of configured providers
*/
@@ -949,10 +980,10 @@ public void load(InputStream is) throws IOException {
}
};
- // load system-wide jakarta.providers from the
+ // load system-wide javamail.providers and jakarta.providers from the
// /{conf,lib} directory
if (confDir != null)
- loadFile(loader, confDir + "jakarta.providers", confDir + "javamail.providers");
+ loadFile(loader, confDir + "javamail.providers", confDir + "jakarta.providers");
//Fetch classloader of given class, falling back to others if needed.
ClassLoader gcl;
@@ -978,10 +1009,10 @@ public void load(InputStream is) throws IOException {
addProvider(p);
}
- // load the META-INF/jakarta.providers file supplied by an application
+ // load the META-INF/javamail.providers and META-INF/jakarta.providers file supplied by an application
loadAllResources(cl, loader, PROVIDER_RESOURCES);
- // load default META-INF/jakarta.default.providers from mail.jar file
+ // load default META-INF/javamail.providers and META-INF/jakarta.default.providers from mail.jar file
loadResource(cl, loader, false, DEFAULT_PROVIDER_RESOURCES);
// finally, add all the default services
@@ -1102,7 +1133,8 @@ private void loadProvidersFromStream(InputStream is) throws IOException {
*/
public synchronized void addProvider(Provider provider) {
providers.add(provider);
- providersByClassName.put(provider.getClassName(), provider);
+ if (!providersByClassName.containsKey(provider.getClassName()))
+ providersByClassName.put(provider.getClassName(), provider);
if (!providersByProtocol.containsKey(provider.getProtocol()))
providersByProtocol.put(provider.getProtocol(), provider);
}
@@ -1117,16 +1149,16 @@ public void load(InputStream is) throws IOException {
}
};
- // load default META-INF/jakarta.default.address.map from mail.jar
+ // load default META-INF/javamail.default.address.map and META-INF/jakarta.default.address.map from mail.jar
loadResource(cl, loader, true, DEFAULT_ADDRESS_MAP_RESOURCES);
- // load the META-INF/jakarta.address.map file supplied by an app
+ // load the META-INF/javamail.address.map and META-INF/jakarta.address.map files supplied by an app
loadAllResources(cl, loader, ADDRESS_MAP_RESOURCES);
- // load system-wide jakarta.address.map from the
+ // load system-wide javamail.address.map and jakarta.address.map from the
// /{conf,lib} directory
if (confDir != null)
- loadFile(loader, confDir + "jakarta.address.map", confDir + "javamail.address.map");
+ loadFile(loader, confDir + "javamail.address.map", confDir + "jakarta.address.map");
if (addressMap.isEmpty()) {
logger.config("failed to load address map, using defaults");
@@ -1156,24 +1188,20 @@ public synchronized void setProtocolForAddress(String addresstype, String protoc
* Load from the named file.
*/
private void loadFile(StreamLoader loader, String ... names) {
- InputStream clis = null;
- for (String name : names) {
- try {
- clis = new BufferedInputStream(new FileInputStream(name));
+ for (int i = 0; i < names.length; i++) {
+ String name = names[i];
+ try (InputStream clis = new BufferedInputStream(new FileInputStream(name))) {
loader.load(clis);
logger.log(Level.CONFIG, "successfully loaded file: {0}", name);
- break;
+ // We already know size is two, but just in case, we don't want to fail here for a logger reason
+ if (i == 0 && names.length == 2) {
+ logger.log(Level.WARNING, "[DEPRECATED] {0} is deprecated and will be removed. Future versions will require {1}.", names[0], names[1]);
+ }
} catch (FileNotFoundException fex) {
// ignore it
} catch (IOException e) {
if (logger.isLoggable(Level.CONFIG))
logger.log(Level.CONFIG, "not loading file: " + name, e);
- } finally {
- try {
- if (clis != null)
- clis.close();
- } catch (IOException ex) {
- } // ignore it
}
}
}
@@ -1182,28 +1210,27 @@ private void loadFile(StreamLoader loader, String ... names) {
* Load from the named resource.
*/
private void loadResource(Class> cl, StreamLoader loader, boolean expected, String ... names) {
- InputStream clis = null;
- try {
- for (String name : names) {
- clis = getResourceAsStream(cl, name);
+ boolean loaded = false;
+ for (int i = 0; i < names.length; i++) {
+ String name = names[i];
+ try (InputStream clis = getResourceAsStream(cl, name)) {
if (clis != null) {
+ loaded = true;
loader.load(clis);
logger.log(Level.CONFIG, "successfully loaded resource: {0}", name);
- break;
+ // We already know size is two, but just in case, we don't want to fail here for a logger reason
+ if (i == 0 && names.length == 2) {
+ logger.log(Level.WARNING, "[DEPRECATED] {0} is deprecated and will be removed. Future versions will require {1}.", names[0], names[1]);
+ }
}
+ } catch (IOException e) {
+ logger.log(Level.CONFIG, "Exception loading resource", e);
}
- if (clis == null) {
- if (expected)
- logger.log(Level.WARNING, "expected resource not found: {0}", Arrays.asList(names));
- }
- } catch (IOException e) {
- logger.log(Level.CONFIG, "Exception loading resource", e);
- } finally {
- try {
- if (clis != null)
- clis.close();
- } catch (IOException ex) {
- } // ignore it
+
+ }
+ if (!loaded) {
+ if (expected)
+ logger.log(Level.WARNING, "expected resource not found: {0}", Arrays.asList(names));
}
}
@@ -1213,7 +1240,8 @@ private void loadResource(Class> cl, StreamLoader loader, boolean expected, St
private void loadAllResources(Class> cl, StreamLoader loader, String ... names) {
boolean anyLoaded = false;
try {
- for (String name : names) {
+ for (int j = 0; j < names.length; j++) {
+ String name = names[j];
URL[] urls;
ClassLoader cld = null;
// First try the "application's" class loader.
@@ -1227,10 +1255,8 @@ private void loadAllResources(Class> cl, StreamLoader loader, String ... names
if (urls != null) {
for (int i = 0; i < urls.length; i++) {
URL url = urls[i];
- InputStream clis = null;
logger.log(Level.CONFIG, "URL {0}", url);
- try {
- clis = url.openStream();
+ try (InputStream clis = url.openStream()) {
if (clis != null) {
loader.load(clis);
anyLoaded = true;
@@ -1245,16 +1271,11 @@ private void loadAllResources(Class> cl, StreamLoader loader, String ... names
} catch (IOException ioex) {
logger.log(Level.CONFIG, "Exception loading resource",
ioex);
- } finally {
- try {
- if (clis != null)
- clis.close();
- } catch (IOException cex) {
- }
}
}
- if (anyLoaded) {
- break;
+ // We already know size is two, but just in case, we don't want to fail here for a logger reason
+ if (j == 0 && names.length == 2) {
+ logger.log(Level.WARNING, "[DEPRECATED] {0} is deprecated and will be removed. Future versions will require {1}.", names[0], names[1]);
}
}
}
diff --git a/api/src/main/java/jakarta/mail/internet/MimeUtility.java b/api/src/main/java/jakarta/mail/internet/MimeUtility.java
index f30ad58d..de0ffa89 100644
--- a/api/src/main/java/jakarta/mail/internet/MimeUtility.java
+++ b/api/src/main/java/jakarta/mail/internet/MimeUtility.java
@@ -40,6 +40,8 @@
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.StringTokenizer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* This is a utility class that provides various MIME related
@@ -139,9 +141,13 @@ public class MimeUtility {
private MimeUtility() {
}
+ private static final Logger LOGGER = Logger.getLogger(MimeUtility.class.getName());
+
public static final int ALL = -1;
// This is for backwards compatibility. Eventually we have to remove the second value of the next array.
+ // Note this order is different than in Session arrays. This is because here the key-value pair is overwritten meanwhile in Session
+ // it checks whether the value was inserted or not already, to avoid @DefaultProvider overrides it.
private static final String[] CHARSET_MAP_RESOURCES = new String[] {"/META-INF/jakarta.charset.map", "/META-INF/javamail.charset.map"};
// cached map of whether a charset is compatible with ASCII
@@ -1353,13 +1359,12 @@ static String getDefaultMIMECharset() {
java2mime = new HashMap<>(40);
mime2java = new HashMap<>(14);
- try {
- // Use this class's classloader to load the mapping file
- // XXX - we should use SecuritySupport, but it's in another package
- InputStream is = resource(CHARSET_MAP_RESOURCES);
-
- if (is != null) {
- try {
+ // Use this class's classloader to load the mapping file
+ // XXX - we should use SecuritySupport, but it's in another package
+ for (int i = 0; i < CHARSET_MAP_RESOURCES.length; i++) {
+ String charsetResource = CHARSET_MAP_RESOURCES[i];
+ try (InputStream is = MimeUtility.class.getResourceAsStream(charsetResource)) {
+ if (is != null) {
LineInputStream lineInput = StreamProvider.provider().inputLineStream(is, false);
// Load the JDK-to-MIME charset mapping table
@@ -1367,15 +1372,14 @@ static String getDefaultMIMECharset() {
// Load the MIME-to-JDK charset mapping table
loadMappings(lineInput, mime2java);
- } finally {
- try {
- is.close();
- } catch (Exception cex) {
- // ignore
- }
}
+ // We already know size is two, but just in case, we don't want to fail here for a logger reason
+ if (i == 0 && CHARSET_MAP_RESOURCES.length == 2) {
+ LOGGER.log(Level.WARNING, "[DEPRECATED] {0} is deprecated and will be removed. Future versions will require {1}.",
+ new Object[]{CHARSET_MAP_RESOURCES[0], CHARSET_MAP_RESOURCES[1]});
+ }
+ } catch (Exception ex) {
}
- } catch (Exception ex) {
}
// If we didn't load the tables, e.g., because we didn't have
@@ -1444,16 +1448,6 @@ static String getDefaultMIMECharset() {
mime2java.put("gbk", "GB18030");
}
}
-
- private static InputStream resource(String[] resources) {
- for (String resource : resources) {
- InputStream is = MimeUtility.class.getResourceAsStream(resource);
- if (is != null) {
- return is;
- }
- }
- return null;
- }
private static void loadMappings(LineInputStream is,
Map table) {
diff --git a/api/src/test/java/jakarta/mail/SessionTest.java b/api/src/test/java/jakarta/mail/SessionTest.java
index 72caa987..6f6e4b61 100644
--- a/api/src/test/java/jakarta/mail/SessionTest.java
+++ b/api/src/test/java/jakarta/mail/SessionTest.java
@@ -16,7 +16,11 @@
package jakarta.mail;
+import java.util.Arrays;
import java.util.Properties;
+import java.util.stream.Stream;
+
+import jakarta.mail.Provider.Type;
import org.junit.Test;
@@ -25,12 +29,31 @@
public class SessionTest {
@Test
- public void issue527() throws NoSuchProviderException {
+ public void issue527And812() throws NoSuchProviderException {
Session session = Session.getInstance(new Properties());
+ Stream providerStream = Arrays.stream(session.getProviders());
+ // test exists in both jakarta.providers and javamail.providers
+ long count = providerStream.filter(p -> "test".equals(p.getProtocol())).count();
+ assertEquals(2, count);
Provider provider = session.getProvider("test");
+ // javamail.providers one has precedence in case of conflict
+ assertEquals(JavaMail.class.getName(), provider.getClassName());
+ provider = session.getProvider("test2");
assertEquals(Jakarta.class.getName(), provider.getClassName());
+ provider = session.getProvider("test3");
+ assertEquals(JavaMail.class.getName(), provider.getClassName());
}
+ @Test
+ public void byProperty() throws NoSuchProviderException {
+ Properties prop = new Properties();
+ prop.put("mail.test4.class", Jakarta.class.getName());
+ Session session = Session.getInstance(prop);
+ // protocol test4 exists in both with same class, but javamail.providers has precedence
+ Provider provider = session.getProvider("test4");
+ assertEquals("OracleMail", provider.getVendor());
+ }
+
public static class Jakarta extends Store {
protected Jakarta(Session session, URLName urlname) {
diff --git a/api/src/test/java/jakarta/mail/internet/MimeUtilityTest.java b/api/src/test/java/jakarta/mail/internet/MimeUtilityTest.java
new file mode 100644
index 00000000..2317596d
--- /dev/null
+++ b/api/src/test/java/jakarta/mail/internet/MimeUtilityTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.mail.internet;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class MimeUtilityTest {
+
+ @Test
+ public void issue812() {
+ // Same value in both files
+ assertEquals("ISO-8859-1", MimeUtility.mimeCharset("8859_1"));
+ // Conflict value, javamail.charset.map wins
+ assertEquals("ISO-8859-1", MimeUtility.mimeCharset("iso8859_1"));
+ // Exists only in javamail.charset.map
+ assertEquals("ISO-8859-3", MimeUtility.mimeCharset("8859_3"));
+ // Exists only in jakarta.charset.map
+ assertEquals("ISO-8859-4", MimeUtility.mimeCharset("8859_4"));
+ }
+
+}
diff --git a/api/src/test/resources/META-INF/jakarta.charset.map b/api/src/test/resources/META-INF/jakarta.charset.map
new file mode 100644
index 00000000..664c0eea
--- /dev/null
+++ b/api/src/test/resources/META-INF/jakarta.charset.map
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2025 Oracle and/or its affiliates.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+8859_1 ISO-8859-1
+iso8859_1 ISO-8859-2
+8859_4 ISO-8859-4
\ No newline at end of file
diff --git a/api/src/test/resources/META-INF/jakarta.providers b/api/src/test/resources/META-INF/jakarta.providers
index b631ea61..ee1e2b44 100644
--- a/api/src/test/resources/META-INF/jakarta.providers
+++ b/api/src/test/resources/META-INF/jakarta.providers
@@ -14,4 +14,6 @@
# limitations under the License.
#
-protocol=test; type=store; class=jakarta.mail.SessionTest$Jakarta; vendor=Oracle;
\ No newline at end of file
+protocol=test; type=store; class=jakarta.mail.SessionTest$Jakarta; vendor=Oracle;
+protocol=test2; type=store; class=jakarta.mail.SessionTest$Jakarta; vendor=Oracle;
+protocol=test4; type=store; class=jakarta.mail.SessionTest$Jakarta; vendor=OracleJakarta;
\ No newline at end of file
diff --git a/api/src/test/resources/META-INF/javamail.charset.map b/api/src/test/resources/META-INF/javamail.charset.map
new file mode 100644
index 00000000..75e7487d
--- /dev/null
+++ b/api/src/test/resources/META-INF/javamail.charset.map
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2025 Oracle and/or its affiliates.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+8859_1 ISO-8859-1
+iso8859_1 ISO-8859-1
+8859_3 ISO-8859-3
\ No newline at end of file
diff --git a/api/src/test/resources/META-INF/javamail.providers b/api/src/test/resources/META-INF/javamail.providers
index bd14849b..0d782852 100644
--- a/api/src/test/resources/META-INF/javamail.providers
+++ b/api/src/test/resources/META-INF/javamail.providers
@@ -14,4 +14,6 @@
# limitations under the License.
#
-protocol=test; type=store; class=jakarta.mail.SessionTest$JavaMail; vendor=Oracle;
\ No newline at end of file
+protocol=test; type=store; class=jakarta.mail.SessionTest$JavaMail; vendor=Oracle;
+protocol=test3; type=store; class=jakarta.mail.SessionTest$JavaMail; vendor=Oracle;
+protocol=test4; type=store; class=jakarta.mail.SessionTest$Jakarta; vendor=OracleMail;
\ No newline at end of file
diff --git a/doc/release/CHANGES.txt b/doc/release/CHANGES.txt
index ea2b4439..61ae6dfd 100644
--- a/doc/release/CHANGES.txt
+++ b/doc/release/CHANGES.txt
@@ -27,6 +27,7 @@ E 744 Remove SecurityManager reference from API
E 758 Improve MimeMessage UTF8 handling
E 804 Restore streamProvider fields for backwards compatibility
E 810 InternetHeaders.InternetHeader toString()
+E 812 Custom mail providers distributed under META-INF/javamail.properties are no longer loaded with Jakarta Mail 2.1.5
CHANGES IN THE 2.1.5 RELEASE
----------------------------
diff --git a/www/docs/COMPAT.txt b/www/docs/COMPAT.txt
index 596701c2..770b01a6 100644
--- a/www/docs/COMPAT.txt
+++ b/www/docs/COMPAT.txt
@@ -3,7 +3,7 @@
-- Jakarta Mail 2.2.0 --
- Removal of finalize()
+- Removal of finalize()
The finalize() methods have been removed throughout the Mail API.
@@ -18,6 +18,20 @@
3. Resource / memory management
Because finalizers are removed, users must more explicitly manage resources: ensure streams, folders, other resources are closed properly. Do not rely on garbage collection / finalization to clean up.
+- Resource Loading Order Update
+
+ In 2.1.4 we introduced a change to prioritize Jakarta-prefixed resources over the legacy ones. However, this unintentionally caused some legacy resources to be skipped entirely.
+
+ As of 2.2.0, the loading logic has been corrected:
+
+ Both legacy and Jakarta-prefixed resources are now loaded.
+
+ Legacy resources take precedence to preserve compatibility.
+
+ Jakarta-prefixed resources remain supported and will take over fully once migration is complete.
+
+ This ensures backward compatibility while still allowing a smooth transition to the Jakarta-based resources.
+
-- Jakarta Mail 2.1.4 --
- Resource Loading Order