-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IMAP not Initializing In Session.getInstance(Properties) #29
Comments
Hi @PeteSL , I am not sure that I understand what is the issue you have. My understanding is that you had one app using IMAP that was working with mail-api 2.0.1 and before, but it does not work with higher versions. From that log lines I don't see what could be the issue. Do you have more relevant logs?. I have a demo that works with IMAP here and I didn't find any problem: https://github.com/jbescos/jakartaEE10MailDemo |
The issue is with angus-mail apparently never getting past the initialization of the Session. I am attaching a zip with 3 log files. err2 log is the log file showing the entirety of the mail output using jakarta-mail 2.1.0/angus-mail 1.0.0. err1 and err0 (in that order) shows the entirety of the mail output using jakarta.mail 2.0.1. There are 2 independent mail clients in this app (maybe part of the issue?) and the basic mail properties are shown in the properties file. mail.debug=true was set for both mail clients and the modules were loaded via the module path. |
@PeteSL are you able to provide the code of the reproducer (you don't need to write host, user and password)?. I will test it and debug it. |
The code below is in the base class constructor (extraneous code removed, the execute method is on a ScheduledThreadPool Executor gotten from Executors).
From the debug log, it looks like it is the sn.getStore() method that is failing as it looks likes like the connect(name, pwd) method is never called? The IMAP properties are: |
I have tried your example and definitely I can connect to IMAP. Try to add e.printStackTrace() in every catch, just in case there is one exception and it is silently failing. Here there is one example sending one email and listing the emails with IMAP. Does it work to you after changing host, port, etc?.
|
Difference is you are doing everything in a single main thread running a single session. My environment has my code being run in separate threads (both session creations are being done in the same thread but the IMAP run() method is in separate threads) and the failure appears to be before the connect() ever occurs according to the log (compare the log outputs in the log files I previously posted). If the exception is anything but StoreClosedException, we would see a stack trace with the exception that is occurring and a StoreClosedException would cause the getStore() method to be called again after 30 seconds which it is not. And since 2.0.1 and prior does not have any issues, I request you try to recreate as shown running 2 different sessions against 2 mailboxes in 2 separate threads. That is the only thing I can think of which would be causing the following apparently when either the getStore() is called or connect() is called:
Considering this is the same place with 2.0.1 is showing "STDOUT: DEBUG IMAP: trying to connect to host". Is 2.0.1 trying to connect as the end of init, getStore(), or connect()? I don't know. In any case, 2.1 (1.0.0) is not performing this connetion attempt but showing that the store is not connected and going straight to cleanup. The connect() method has never required a pre-existing connection in a connection pool as this would require the server and network to always be in place which is not a valid assumption. Even so, it appears the server is never being connected to, according to the debug logs, so this brings me back to the multi-session, multi-threaded environment I am working in which was not in your example. |
Hi @PeteSL I have added one example where 2 threads are reading available emails with IMAP protocol in a while true. The thread hangs during one second having the connection open, to make sure the other thread is able to open another connection in parallel. I didn't find the issue. Could you try it too?:
Output:
|
You are using a single session using getDefaultInstance() which is not usable in my situation where the 2 sessions must be independent. In my app, the 2 integral clients are completely independent in their stores (and transports) which is typical in any client where multiple mailboxes are being supported. For your tests, you must use multiple getInstance() methods in different threads which then will use independent stores in other threads. For instance (mail properties not shown):
|
@PeteSL I have tried that too and it is working. In this case both sessions are connecting to the same host:port. I cannot imagine why it is not working in your case. Each session instance is isolated, so having multiple threads should not make an issue. This is the example with the modification:
|
The difference I see is your getStore is in the same thread as the Session.getInstance(). Try using an unbounded thread pool (or up your number of threads to 4) and have the store access in a different thread from the Session.getInstance(). Also, set up 2 mailboxes with 2 different from addresses (can be same server) to ensure there is no bleed over between sessions. As I have said and the logs show, there is no difference in my code from 2.0.1 (and prior going back to 1.6.x) and using the 2.1.0 and Angus 1.0.0 packages/modules. but with 2.1.0/Angus 1.0.0 there is no attempt to connect to the server with either session and both sessions go directly to cleanup (either when connect() is called or getStore() is called, from what I can figure from the logs). One last thing: in my code, the thread that creates the session is gone after the session is created. This is true in my example and in my code so if any ThreadLocal methods/variables are being used in the session instance, they will be gone by the time the actual connection code gets executed. |
In my base code, the Session.getInstance() is in the class constructor. This means that it is possible the session instances are created on the same thread but the code that calls getStore() and connect() are on independent threads from executors. So your test could be
This would create the sessions on the same thread (which might disappear) similar to my production code but the store access will be on different threads. Again, be sure to use different mailboxes (same server ok) so no ThreadLocal interference. |
Here is the new way. The session is created in a new thread and I added a new IMAP port to connect.
This is the output:
|
Can you try the way I showed (main() creates the session on that thread but uses a cached thread pool for executing the store accesses)? Also, can you set up 2 different from addresses (mailboxes)? In my production environment, everything is the same between the 2 integral clients except the from address, user name, and password. Again, what we are trying to determine is what is causing Angus 1.0.0 go straight to cleanup saying no connections instead of even trying to connect. I am trying to provide as close an example to my production environment as I can considering threads, mailboxes, etc. I use no system properties that would directly affect jakarta.mail. I have provided the properties files which you are properly duplicating. And the run code that is actually accessing the store/mailbox has been shown above. I am asking where is the difference in the getStore()/connect() mechanism between 2.0.1 (and before) and 2.1.0/Angus 1.0.0 that would cause the connect sequence in earlier implementations but not now? Is there a difference in using SocketChannel instead of Socket? Is there a difference in defaults which needs to be addressed in the properties? I don't know but I am asking the question because, at this time, 2.1.0 is non-functional with my app yet all prior versions work on Java 8 through Java 19 (jakarta.mail with Java 11 on). |
I tried it like this, but it also works:
I have the IMAP server in a docker image. I created 2 containers of the same image. One is for port 18004 and the other for port 18014. These are 2 different addresses. In mail 2.1.0, the only change was to make a split between API (jakarta.mail:jakarta.mail-api) and implementation (org.eclipse.angus:angus-mail). There are no changes related to sockets, improvements, etc. Could you remove your dependency jakarta.mail and replace it by the next?:
|
I am not using Maven. This is a production app and has no project settings. It is being run with everything on the module path, all modules on the module path are being added, and it is running as a modular Java application as it should be. There were other changes in the implementation (SSL issue showed a change from Socket to SocketChannel for SSL connections, for instance). You are still creating each session on different threads which is not what my code is doing. In my app and example, the sessions are being created on the same thread but the store accesses are on different threads. In your example, you are using the same user name/email from address for both stores. In my case, the user name/from address is different but the server is the same. |
Can you print down the module path?, so I can see the mail, activation and angus dependencies. What other changes related to SSL do you mean?. The thread is created in a thread pool (ExecutorService singleThread = Executors.newSingleThreadExecutor();) that contains only one thread. So the same thread is creating 2 sessions. I have changed the user and keep the same address, and it is working too. Here it is:
|
As shown in my main() example, I do not use an executor to create the sessions but ok, I understand what you are saying about the single thread being reused although I believe the thread is reinitialized between uses by the single thread executor so there is no bleed over of ThreadLocal variables, etc. The module path is application.jar;lib (running on Windows so semicolon) where lib contains all the rest of the application jars. The mail jars in the lib folder are jakarta.activation-api-2.1.0.jar, angus-activation-1.0.0.jar, jakarta.mail-api-2.1.0.jar, angus-mail-1.0.0.jar, dsn-1.0.0.jar and I have --add-modules ALL-MODULE-PATH. When running 2.0.1, activation remains the same but the angus mail jars are removed (dsn-1.0.0.jar, angus-mail-1.0.0.jar, and jakarta.mail-api-2.1.0.jar) and replaced with jakarta.mail-2.0.1.jar and dsn-2.0.1.jar. The other thing I do is my properties has mail.store.protocol=imap That shouldn't make a difference but... If you turn on mail.debug=true, are you seeing the same sequences I provided in 2.0.1 or 2.1.0? I did not edit out anything in those sequences in the logs I provided (log 2 is 2.1.0, log 1 then log 0 is 2.0.1). |
If you are using Folder.idle then you can't use SocketChannel Since you are using ScheduledThreadPoolExecutor all runnables are wrapped in a FutureTask. This FutureTask can trap and hold java.lang.Error objects. These error tend to skip by catch blocks which is a problem if Future::get is not called to extract that error. In your Runnable add:
This will help troubleshoot if there is a problem with say a LinkageError or ServiceConfigurationError |
That is why I asked if there was a change in defaults because I have never used SocketChannel. I can add a catch (Exception ex) to the run task but that will have to wait until I am back in the office this evening. |
Don't catch Exception but rather catch java.lang.Error and java.lang.RuntimeException |
We now have the answer:
This error does not occur with 2.0.1 because there is no module com.sun.mail; these are all exported packages in the jakarta.mail module. This is where modules are going to get us caught. If I try to use the jakarta.mail jar that has angus bundled with the API, dsn won't work because dsn.jar requires module com.sun.mail. So we have a module issue where the implementation module, com.sun.mail, is overriding the API exposed definitions which would require a special module.class file just for 2.1.0 which would not be compatible with any prior versions. Current workaround for any application which was working with 2.0.1 is to add the following to the command line: |
I have commented on #32 and also think that the release notes need to call out that a new module is being used for any references to com.sun.mail packages (like com.sun.mail.imap) and the --add-reads command line argument must be used with applications written for prior versions jakarta.mail, specifically for 2.0. |
Using --add-reads for modules compiled pre-Angus mail works well. If you are compiling to Jakarta Mail 2.1.0/Angus Mail, use the following in your module-info.java to maintain compatibility with the bundled Jakarta Mail and with Jakarta Mail 2.0.1:
|
It was solved here: #32 We can close this. |
I have an app that works with jakarta.mail 2.0.1 and before. I set the log.level to FINE so we could see everything generated at startup and this is it:
I am using the patched jakarta.mail-api jar from #25 so we don't see those errors. It appears the Session has an issue setting up the connection (not SSL, just plain text as on LAN), The Session.getInstance() is by itself, does not throw an exception (I would see this with a stack trace) but it appears no other parts following it are executed including the SMTP transport setup? This is all that was in the log related to jakarta.mail which seems to tell me that the Session.getInstance() is never returning? The only change from 2.0.1 is the jakarta.mail jars that are being used. I do not use the IdleManager; the app calls idle(boolean) directly but that part is never shown in the log. JDK is 19.
The text was updated successfully, but these errors were encountered: