I'm reading and processing emails received from IMAP using JODD mail library. API is very nice but I struggle with one logical issue. I'm using code as following:
EmailFilter filter= new EmailFilter();
filter.flag(Flags.Flag.SEEN, false);
session.receiveEmailAndMarkSeen(filter);
By calling session.receiveEmailAndMarkSeen I receive all unread emails and these are marked as read immediately. Now when processing fails in my code for any reason, and I try to receive emails again all these unprocessed emails are marked as read already and not downloaded anymore. I would rather download emails and mark them as read individualy as beeing processed successfully.
So I tried to receive them with session.receiveEmail but not sure how to mark them as read when processed? Any hint how to do it? I can see that email object has 'flag' property I can set but not sure how to send this information back to server.
To summarize possible solutions:
Re-fetch email with Seen flag. The downside is that email is fetched again.
What you wrote - using a Session and a Folder.
Finally - starting from the next version of Jodd, you will have the method updateEmailFlags that would give you options to just call it:
mymail.flags(newFlags);
ReceiveMailSession.updateEmailFlags(mymail);
The result would be the same.
SOLVED: I'm creating connection manualy using common JAVA mail classes - Session and Store.
Session sess = Session.getDefaultInstance(props, null);
Store store = sess.getStore("imaps");
store.connect("imapServerHost", "username","password");
... then I create folder object (points to Inbox)
Folder folder = store.getFolder(this.imapFolder);
folder.open(Folder.READ_WRITE);
... then I receive emails using session and store
ReceiveMailSession session=new ReceiveMailSession(sess, store);
... after email processed, I send back SEEN=true message using folder object.
Flags f=new Flags();
f.add(Flags.Flag.SEEN);
folder.setFlags(new int[] {email.getMessageNumber()}, f,true);
Related
I have a scenario like this. I have copied a gmail message from Inbox to a child folder of Inbox, say test-folder. Now the message is there in Inbox and as well as in Inbox/test-folder. Now later if I want to delete (expunge) the copy in Inbox/test-folder using javamail, it is also being deleted from Inbox also.
I know that gmail maintains only 1 copy of the message in its database and it just tags folder names to the message, so it is obvious if I expunge it from other folder, it will also get deleted from the original folder.
The following code works for other IMAP based mails like yahoo and etc.
Folder inbox = store.getFolder("INBOX");
Folder child = store.getFolder("INBOX/test-folder");
inbox.open(Folder.READ_WRITE);
child.open(Folder.READ_WRITE);
AppendUID[] appendUIDs = inbox.copyUIDMessages(new Message[]{ message }, child);
AppendUID appendUID = appendUIDs[0];
long uid = appendUID.uid;
// EDIT: I have to close and reopen the child folder, otherwise getMessageByUID will return null.
child.close(false);
child.open(Folder.READ_WRITE);
Message copiedMessage = child.getMessageByUID(uid);
if (!copiedMessage.isExpunged() && !copiedMessage.isSet(Flags.Flag.DELETED)) {
copiedMessage.setFlag(Flags.Flag.DELETED, true);
}
inbox.close(true);
child.close(true);
The above code delete only the message in Inbox/test-folder, not from Inbox for Yahoo and all. But for gmail it deletes the message from Inbox as well as Inbox/test-folder.
Email client like evolution, handles this scenario properly for gmail. It deletes the message only from the target folder. So how to achieve this using javamail or gimap library?
NOTE: I am using 1.5.5 of the javamail library.
Seems like that should work, but Gmail doesn't exactly follow the imap spec. What does the debug output show?
I have a piece of code which uses spring integration's IMAP adapter to poll an inbox to read all incoming emails which are unread and that works perfectly. But if I open any email message and and then mark it as "unread" in my outlook inbox the poller doesn't fetch the marked email.
I can use the pop3 adapter which fetches all the email, but deletes them afterwords, but I want to keep the emails in my inbox and I want the poller to fetch all the email which are unseen.
Any suggestions to handle this problem? I been searching and reading articles on email adapters but didn't find anything useful.
Thanks in advance.
Looks like you need custom 'search-term-strategy'. From Spring Integration (SI) documentation:
By default, the ImapMailReceiver will search for Messages based on the default SearchTerm which is All mails that are RECENT (if supported), that are NOT ANSWERED, that are NOT DELETED, that are NOT SEEN and have not been processed by this mail receiver (enabled by the use of the custom USER flag or simply NOT FLAGGED if not supported). Since version 2.2, the SearchTerm used by the ImapMailReceiver is fully configurable via the SearchTermStrategy which you can inject via the search-term-strategy attribute. SearchTermStrategy is a simple strategy interface with a single method that allows you to create an instance of the SearchTerm that will be used by the ImapMailReceiver.
And here is a post from SI forum with funtastic Oleg's explanation: Server does not support RECENT or USER flags
And here you can find SI DefaultSearchTermStrategy: it's a place to determine how you should implement your own strategy. I guess, you case is:
This email server does not support RECENT flag, but it does support USER flags which will be used to prevent duplicates during email fetch.
Switch SI-mail logging level to DEBUG and take a look, which flag supports your email server.
Here is what I am trying to do:
Add a special button to attach files to Notes "New message" window. If files were attached using this button, when email sent, they should be uploaded to the server and link to them added to the email.
My question - is it possible (and how) to capture "send mail" event in the plugin for Lotus Notus?
I don't know how an Eclipse plugin would do this. Furthermore, since Notes can be used off-line -- when it would be impossible to upload files to a server -- it would be better to have code running on the Domino server intercept the mail messages and perform the upload.
Most products that hook mail operations on the server use the Lotus Notes C API's Extension Manager functions to hook the EM_BEFORE notification for the EM_NSFNOTEUPDATE event and check whether the NSFNoteUpdate operation occurred within the server's mail.box files, and then check whether the the message requires special processing (i.e., in your case that would be by looking for a special NotesItem that your button code has inserted into the message). The usual coding method for this is to immediately change the status of the message to put it on hold, preventing the Domino router from attempting to send the message while your code is still working on it. Many products actually have two components - the EM hook DLL and a separate server task that receives a signal from the hook DLL, processes the message, and then releases it from on hold status. This approach keeps your code from tying up router threads while processing large files.
(Note: Newer versions of the Domino server have the ability to use OSGI plugins written in Java instead of using the Notes C API for operations like this. I've not looked into the details of how this might work for operations that process mail messages. )
I sort of figured it out. There is a very nice extension point provided in 8.5 - "com.ibm.notes.mailsend.MailSendAttachmentsDialog", that is specifically exists for custom handling of attachments. You can see it in plugin.xml, in IBM\Lotus\Notes\framework\shared\eclipse\plugins\com.ibm.notes.mailsend_8.5.*.jar.
The only problem is - it handles just attachments and does not have access to anything else. So if somebody figured how to get subject line and the message text from there, please reply.
Update: got it.
NotesUIElement elem = (new NotesUIWorkspace()).getCurrentElement();
if (elem instanceof NotesUIDocument) {
NotesUIDocument doc = ((NotesUIDocument) elem);
String to = doc.getField("EnterSendTo").getText();
String cc = doc.getField("EnterCopyTo").getText();
String bcc = doc.getField("EnterBlindCopyTo").getText();
String subject = doc.getField("Subject").getText();
String body = doc.getField("Body").getText();
....
}
I display the progress bar for downloading attachments and it works fine … but when I am downloading some attachments I get the exception message:
Exception in thread "main" com.sun.mail.util.DecodingException:
BASE64Decoder: Error in encoded stream: needed 4 valid base64
characters but only got 1 before EOF, the 10 most recent characters
were: "Q3w5ilxj2P"
I found the explanation:
Certain IMAP servers do not implement the IMAP Partial FETCH
functionality properly. This problem typically manifests as corrupt
email attachments when downloading large messages from the IMAP
server. To workaround this server bug, set the
"mail.imap.partialfetch" property to false. You'll have to set this
property in the Properties object that you provide to your Session.
http://java.sun.com/products/javamail/NOTES113.txt
So I turned off partial fetch:
Properties props = System.getProperties();
props.setProperty("mail.store.protocol", "imaps");
props.setProperty("mail.imaps.partialfetch", "false");
Session session = Session.getDefaultInstance(props, null);
Store store = session.getStore("imaps");
store.connect("imap.gmail.com", "<username>","<password>");
this solved the problem ….however the method getInputStream() from the Part class blocks the thread until the attachment is completely downloaded and it is impossible to get the information about the number of bytes which have been already downloaded from mailbox.
Without this information it is impossible to display the progress bar. So is there a way to obtain this information and display the progress bar?
It's difficult.
The only approach I know of is to create your own socket factory that produces a special kind of socket (of your own design) that returns an InputStream that wraps the real socket InputStream and allows you to monitor the amount of data read through the stream. This will allow you to measure the IMAP protocol data that is being returned from the server to the client. It won't be able to tell you what percentage of the data has been returned (because the data you're measuring includes all the IMAP protocol overhead and encoding overhead), but it should allow you to see that progress is being made.
If you create something like this, I'm sure others would be very interested in it!
I want to create an application that gets all e-mails from an e-mail account using imap.
When I first run the application I get all mails, than if I run it again I want to mark the messages that was read before so I can receive only new messages.
I found that Message Object contains Flags(System Flags and User defined flags), but I can't manage to set one user defined flag.
It is possible to mark the messages received by my application on the e-mail account, or I have to retain all message ids and every time when I get messages from imap I have to compare their id with retained ids and get only the messages that has different ids?
Some IMAP servers don't permit you to set user-defined flags. Most do, however. Via JavaMail, you'd do the following:
Flags flags = new Flags("fetched");
message.setFlags(flags, true);
Those flags aren't permanent, however -- another IMAP client could clear them just as easily as you set them. (Though they probably won't.)
Another option is to track the UIDs of the messages you've seen. You can get them via ImapFolder.getUID(Message). It's more straightforward than tracking Message-ID headers, which are much more costly to fetch and, since they're strings, occupy more memory in your app.
Yet another option is to use POP and track UIDLs.
Yes it is possible to mark the messages as read, and when the next time you want to read the messages you can only read the new messages.
Use the following code:
Folder emailFolder = emailStore.getFolder("INBOX");
Message messages[] = emailFolder.search(new FlagTerm(new Flags(Flag.SEEN), false));
System.out.println("no of messages=" + messages.length);
for (int i = 0; i < messages.length; i++) {
Message message = messages[i];
//here write your code to read the message and whatever you wanna do//
//now at the end of the message(remember at the end of the message u read using code) write the following code//
message.setFlag(Flag.SEEN, true);
}//end of for loop