Reading mail form IMAP server using javax.mail - java

I'm trying to read messages from IMAP folders using javax.mail, but after fetchig few messages Im getting following exception:
* 20 FETCH ()
DEBUG IMAPS: ignoring bad response, THROW:
com.sun.mail.iap.ParsingException: error in FETCH parsing, unrecognized item at index 12, starts with ")
at com.sun.mail.imap.protocol.FetchResponse.parse(FetchResponse.java:219)
at com.sun.mail.imap.protocol.FetchResponse.<init>(FetchResponse.java:96)
at com.sun.mail.imap.protocol.IMAPProtocol.readResponse(IMAPProtocol.java:392)
at com.sun.mail.iap.Protocol.command(Protocol.java:354)
at com.sun.mail.imap.protocol.IMAPProtocol.fetch(IMAPProtocol.java:2113)
at com.sun.mail.imap.protocol.IMAPProtocol.fetch(IMAPProtocol.java:2094)
at com.sun.mail.imap.IMAPFolder.fetch(IMAPFolder.java:1253)
at app.mail.imap.ImapClient.synchronizeLocalData(ImapClient.java:563)
at app.mail.imap.ImapClient.lambda$6(ImapClient.java:351)
at java.lang.Thread.run(Thread.java:745)
* BYE Internal error occurred. Refer to server log for more information. [2016-11-03 21:20:44]
This is the code Im using to read messages (session, store and folder are already opened):
final Message[] messages = imapFolder.getMessagesByUID(1, IMAPFolder.LASTUID);
final FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
fp.add(FetchProfile.Item.FLAGS);
imapFolder.fetch(messages, fp);
for (final Message msg : messages)
{
final long uid = imapFolder.getUID(msg);
final String subject = MimeUtility.decodeText(msg.getSubject());
final Date date = msg.getReceivedDate();
info("MESSAGE: {} -> {} on {}", uid, subject, date);
}
It seems it's happening only on very specific messages and only when fetching more informations than message UID (if Im reading only uid then code works).
As far as I know many IMAP servers implementations lack many features from IMAP protocol. Bearing that in mind, what is safest and most reliable method for fetching and reading messages from IMAP folders?
javax.mail version: 1.5.3 (provided by wildfly app server 10.0.1.Final).

Thanks for your help. It seems it is indeed IMAP server error. When I'm opening message in web client i get:
Connection error (#022).
Also KMail do not download messages for that folder (I bet other clients too).

Related

Aerospike Java Client Error Message : Error -3,1,0,30000,0,2: Cluster is empty

Reading record from aerospike gives cluster is empty exception.Also the error occurs for few requests. Operations(read/write) are working fine for most of the requests but few requests randomly gives this exception
com.aerospike.client.AerospikeException$InvalidNode: Error -3,1,0,30000,0,2: Cluster is empty
I am using java client version 5.1.11
Below is the code to read :
new AerospikeClient(hostName,port);
#Autowired
private AerospikeClient client;
client.get(policy, key);
Not sure if thats exactly your case, but few years ago there was a similar case of "Error -3: InvalidNode" exception on few of the requests - after investigating the user found that it was a network issue (spikes caused 200Mbps while the network channel size they had was 100Mbps).
you can read about it here: https://discuss.aerospike.com/t/aerospike-c-client-error-code-3/4160/5

Websocket ClientEndpoint OnMessage-method not called when large String (length 20000) is sent

1) Using javax.websocket.ClientEndpoint and javax.websocket.OnMessage with JavaSE-1.8
2) Server (built with Annotations) sends String with length 20000:
#ServerEndpoint("/websocket")
public class MyEndpoint {
#OnMessage
public String onMessage(String message, Session session) {
session.getBasicRemote().sendText( "eg String with length 20000 .... ... ..." );
}
}
3) Client sends request and should receive String from server (example just receives):
#ClientEndpoint
public class Receiver {
#OnMessage
public void processMessage(String message, Session session) {
System.out.println("Message received: " + message );
}
}
But:
No Message is received by client. Shorter strings eg length 500 work.
No exception is raised at server (if try-catch used).
So - the sent string with Length 20000 disappears without any error !
A browser which sends the request to the server receives the string from the server and everything works, so problem has to be at client.
Also the implementation org.java_websocket.client.WebSocketClient receives the String from the server.
I also tried to set MaxTextMessageBufferSize with
session.setMaxTextMessageBufferSize(25000);
Where is the bug?
Where do i have to report this bug to get a working client for larger strings?
The implementation of javax.websocket is pretty nice with its session-IDs and i do not want to wrap org.java_websocket.client.WebSocketClient just because of this single bug in javax.websocket.ClientEndpoint ?
Thanks.
Sounds like a server configuration issue or bug.
(Hard to narrow down how to help, as you didn't tell us what kind of server you are using)
Most modern javax.websocket servers can handle multi-megabyte message sizes with ease.
These work great:
Jetty 9.2.x+
Tomcat 8.x+
Wildfly/JBoss 8.x+
All of those have excellent websocket support and configuration options.

How to read the UNREAD email using java mail api

I am trying to read the UNREAD mails from gmail account. I tried to filter the messages based on the Flags, but it did not work. I printed the Flags sent on each message, but nothing is set on it, because of which I could not filter the messages. I used the keyword Flags.Flag.SEEN to filter the messages.
After googling, I found out that it is something with the email client. For ex, we need to the change the configuration in gmail or any exchange mail server. Can you please tell me on what to change the configuration to read the UNREAD mails?
Also, end of day, I am going to implement the code into one of the smtp exchange servers. Please let me know if there needs a special configuration. So that I can inform the respective team and then implement my change.
// connects to the message store
Store store = session.getStore("pop3");
store.connect(userName, password);
// opens the inbox folder
Folder folderInbox = store.getFolder("INBOX");
System.out.println("unread count - " + folderInbox.getUnreadMessageCount());
folderInbox.open(Folder.READ_WRITE);
// folderInbox.search(new FlagTerm(new Flags(Flags.Flag.RECENT),
// false));
// fetches new messages from server
Message[] arrayMessages = folderInbox.search(new FlagTerm(new Flags(Flags.Flag.RECENT), false));
The POP3 protocol doesn't support any flags. Use IMAP.
See Retrieving all unread emails using javamail with POP3 protocol.
One comment suggests the use of Flags.Flag.SEEN for Gmail. There's another suggestion about changing settings in your test Gmail account.

SMTP not able to send group mail

I need to send a group mail as a part of batch job. I'm using javax.mail package to accomplish this.
Properties m_properties;
m_properties = new Properties();
m_properties.put("mail.smtp.host", "localhost");
m_properties.put("mail.smtp.port", Integer.toString(26));
Session m_Session = Session.getDefaultInstance(m_properties);
Message m_simpleMessage = new MimeMessage(m_Session);
InternetAddress m_fromAddress = new InternetAddress("me#sample.com");
InternetAddress m_toAddress = new InternetAddress("group#sample.com");
m_simpleMessage.setFrom(m_fromAddress);
m_simpleMessage.setRecipient(RecipientType.TO, m_toAddress);
m_simpleMessage.setSubject(m_subject);
m_simpleMessage.setContent(m_body, "text/html");
Transport.send(m_simpleMessage);
I'm using a windows server. I installed IIS SMPT server and using it. I have no problem when I send a mail to individual id. But I get an error when trying to send to a group.
Error :
This is an automatically generated Delivery Status Notification.
Delivery to the following recipients failed.
group#sample.com
Do I need to configure something in my SMPT server for a group, or do I need to make changes in my code for allowing to send a group mails.
The group must exist in the destination server... Does the destination smtp server you are reaching contains the group?

How to Send bulk mails using javax.mail API efficiently? & Can we use reuse authenticated sessions to improve speed?

I am able to send a mail using javax.mail API. But the problem here is on an average for each mail it taking around 4.3 seconds to send to destination.
If I am sending a 20 mails sequentially, it takes around 86.599 seconds. For my requirement this approach will not work. I am looking for an approach which can send large number of mails in less time.
When I looked at the debug log, the API is trying to authenticate to SMTP server for each and every message it sending. But I am creating a session only one time and using the same session for all the mails I am sending. Now my question is Isn't it a overhead process every time authenticating itself to the smtp server. Isn't there a better approach ?
Below is the log trace you may find helpful.
250-AUTH LOGIN PLAIN XOAUTH XOAUTH2
250 ENHANCEDSTATUSCODES
DEBUG SMTP: Found extension "SIZE", arg "35882577"
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "AUTH", arg "LOGIN PLAIN XOAUTH XOAUTH2"
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: Attempt to authenticate
DEBUG SMTP: check mechanisms: LOGIN PLAIN DIGEST-MD5 NTLM
DEBUG SMTP: AUTH LOGIN command trace suppressed
DEBUG SMTP: AUTH LOGIN succeeded
Please let me know your thoughts on this and any help on this is really appreciated.
-Narendra
How are you sending the messages? The JavaMail FAQ suggests that the static Transport.send method will open a fresh connection for each message, as it is a convenience method that creates a suitable Transport instance, connects it, calls sendMessage and then closes the connection again. If you get your own Transport instance from the Session you can connect once, then call sendMessage repeatedly to send several messages on the one connection, and finally close it. Something along the lines of (untested):
Transport t = session.getTransport();
t.connect();
try {
for(Message m : messages) {
m.saveChanges();
t.sendMessage(m, m.getAllRecipients());
}
} finally {
t.close();
}
Updated to use try with resources block:
try (Transport t = session.getTransport()) {
t.connect();
for(Message m : messages) {
m.saveChanges();
t.sendMessage(m, m.getAllRecipients());
}
}
I got the same requirement at work. I must send bulk emails and standalone email. I do not find simple and satisfactory answer: bulk emails can be sent using a single connection but standalone email cannot until I create an asynchronous buffering to send emails in batch.
Last but not least, using a lot of Transport connection in a short time can lead to a no more socket handles are available because all ports are stuck in the TIME_WAIT state.
I finally conclude the best will be an SMTP connection pool and because no library exists (at least free) I create mine using Apache Common Pool and Java Mail:
//Declare the factory and the connection pool, usually at the application startup
SmtpConnectionPool smtpConnectionPool = new SmtpConnectionPool(SmtpConnectionFactoryBuilder.newSmtpBuilder().build());
//borrow an object in a try-with-resource statement or call `close` by yourself
try (ClosableSmtpConnection transport = smtpConnectionPool.borrowObject()) {
MimeMessage mimeMessage = new MimeMessage(session);
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, false);
mimeMessageHelper.addTo("to#example.com");
mimeMessageHelper.setFrom("from#example.com");
mimeMessageHelper.setSubject("Hi!");
mimeMessageHelper.setText("Hello World!", false);
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
}
//Close the pool, usually when the application shutdown
smtpConnectionPool.close();
The above answers are either not relevant or too complex to implement. So here's I am posting the easiest solution to send bulk emails in Spring Boot
Just use
mimeMessageHelper.setBcc(emailList);
Where,
mimeMessageHelper is MimeMessageHelper, emailList is String[] emailList
NOTE:
Make sure that you are not using
mimeMessageHelper.setTo(emailList)
Otherwise, it will show all receivers' email address in the receiver's received email.
For more reference, This and This can help you to learn how to send emails in Spring Boot
No idea if the standard Java mail API allows what you are trying to accomplish (session reuse), but you may consider using multi-threading:
I would use a ThreadPool and submit mail send jobs to it. Then you do any error handling / resending within the job class code, which is executed by the ThreadPool asynchronously, and your main thread can resume to do other things. Submitting a job will only take milliseconds. It been a while since I implemented something with thread pools in Java, but I remember it was fairly easy and straightforward. If you Google "Java ThreadPool" you find plenty of material.
I developed a way to send 1000 emails in less than 1 min. This email has only text. Heavy HTML takes approx 2 mins.
#Async("bulk-email")
void sendBulkEmail(List<EmailMessage> emailMessages){
// EmailMessage is a custom object with properties like to, cc, subject.
Collection<List<EmailMessage>> partitionedList = Lists.partition(emailMessages,
50); // Google Guava library.
try{
ForkJoinPool customThreadPool = new ForkJoinPool(10);
customThreadPool.submit(()->
partitionedList.parallelStream.forEach(this::sendEmails)).get();
}catch(Exception e){
e.printStackTrace();
}
}
This will create 10 threads with each thread will send 50 emails with one Session and one connection.
private void sendEmails(List<EmailMessage> messages){
Session session = createSession();
try (Transport t = session.getTransport()) {
t.addTransportListener(transportListener);
t.connect();
for(Message m : messages) {
MimeMessage mime = createMimeMessage(session, m);
mime.saveChanges();
t.sendMessage(mime, mime.getAllRecipients());
}
}catch(Exception e){
e.printStackTrace();
}
}
You can use Thread pooling as it gives very good performance.I have implemented and sharing you the below code snippet.
try {
ExecutorService executor = Executors.newFixedThreadPool("no. of threads"); // no. of threads is depend on your cpu/memory usage it's better to test with diff. no. of threads.
Runnable worker = new MyRunnable(message); // message is the javax.mail.Message
executor.execute(worker);
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
}

Categories