reason for why all messages are parsed even if not needed?
maxandersen opened this issue · comments
I'm mainly interested in processing/filtering mail and jodd mail fluent interface is awesome to express it BUT at the moment jodd mail forces parsing/init of Message content that is (at least for my usecase) unnecessary.
Example:
session.receive().filter(filter().to("me@mail.com")).moveToFolder("somewhere").get();
This call which is intended to simply take all emails sent to me@mail.com
and move it to somewhere
This should mainly just result in 2 queries to the imap server. 1 for the query, 1 for the move/cope operation.
What does happen instead in case there are 500 messages matching:
1 query
500+ fetches
500+ updates to unset SEEN
1 for move
This all happens because of all messages are processed and then unset flag.
Is there a reason why this is done for all kind of searches and aren't an optional thing?
the fetches seem to be when getFlags/getHeaders called and if not envelope then all bodies are fetched too.
How about ReceiveMessages lazily did this rather than upfront?
Or maybe introduce a .getResult()
method which returns a ReceiveResults
which wraps Messages[] array so one avoid doing all that fetching unless really need it?
I guess the main reason for this is that library wraps both POP3 and IMAP...
But you are right, we should add some lazy fetching... let me see.
@maxandersen here is the thing:
session.receiveMessages(filter, flagsToSet, flagsToUnset, envelopeOnly, messages -> {
if (targetFolder != null) {
try {
session.folder.copyMessages(messages, session.getFolder(targetFolder));
} catch (MessagingException e) {
throw new MailException("Copying messages failed");
}
}
});
the problem is with the session.folder.copyMessages
as it requires Message[]
as input. Even IMAPFolder
implementation has moveMessages
that has Message[]
as input.
The first thing receiveMessages
do is to get messages from the folder.
if (filter == null) {
messages = folder.getMessages();
} else {
messages = folder.search(filter.getSearchTerm());
}
So I am not sure how to get lazy the Message[]
from the folder
so I can use the move later...
But the Messages[] are not filled in. So they are "lazy" by default.
To avoid having to convert to ReceiveMessage Im suggesting to have a SearchResult intermediære that keeps Message[] around and then only convert to ReceiveMessage if absolute necessary.
I got it, I was not expecting messages[] not filled in :)
Here is the attempt: #13
Your expression would be written as:
session.receive().filter(filter().to("me@mail.com")).moveToFolder("somewhere").run();
We need to find a better name for
run()
, it is just a temporary one.
What I still have to figure out is the method:
What can we/should execute right away and what is ok to be delayed in the _fetch()
method?
Any chance you saw the change @maxandersen ? Maybe I can build a snapshot so we can test?
@igr sorry - I did see it and I thought I commented already but apparently that didn't "stick" :)
So I like the idea but I can say that my current approach is that I have the filters and action separated - and that works nicely as it allows me to reuse the filter definition for both bulk operations and where I have a set of mails needing to filter manually.
My question is what would 'session.receive().filter(...)..run()' return ?
and would it be possible to have session.recieve().filter(...).do(Actions::myCustomAction).run()
?
snapshot would be nice to try or simply a PR then I can use it more or less directly with jitpack.
the PR is open already: #13 :)
I just added with(consumer).run()
method chain.
Friendly ping :)
sorry - completely missed this. trying it out now :)
looks good - works for a nice fluent solution!
Thanx you @maxandersen !!! Will prepare a release :)
Merged!