Continue for loop after exception java - java

This is my code:
if (Recipients_To != null) {
for (int i = 0; i < Recipients_To.length; i++) {
message.setRecipients(Message.RecipientType.TO, Recipients_To[i].toString());
Transport.send(message);
}
}
I have more than 500 Recipients list to send mail and this code will send personal mail to each recipients. But if i got exception in between this for loop i want to continue loop for remaining recipients. How can i do?

You want to use try catch blocks to do this, like so
for (int i = 0; i < Recipients_To.length; i++)
{
try {
message.setRecipients(Message.RecipientType.TO,Recipients_To[i].toString());
Transport.send(message);
}
catch (YourException e){
//Do some thing to handle the exception
}
}
This catches the potential issue and will still continue with the for loop once the exception has been handled.

You can catch the exception e.g.
try {
message.setRecipients(Message.RecipientType.TO, Recipients_To[i].toString());
Transport.send(message);
} catch (Exception e) {
// handle it or leave it be
}

Technically, it's simply a matter of catching the exception (see Murat K's answer). I would recommend, however, that since you're sending e-mail, that you do cease sending the rest when the first exception occurs, unless you are certain that it is an error you can safely ignore. A few examples of things that can go wrong:
Invalid credentials: this means that if you continue attempting to send, every subsequent attempt will also fail. Best case: no e-mail sent. Worst case: SMTP server blocks your access due to excessive login failures.
Malformed recipient address: no issue to continue trying the other addresses, but you need to do something with this error (remove recipient from list for future mailings)
Misconfigured mail server address: each iteration of your loop will try to connect to the mailserver, and fail. This will slow down the method tremendously (server timeouts) or spam your log (assuming you did something with the exception)
So please consider your course of action carefully when handling e-mail.

You can try something like this
if (Recipients_To != null) {
for (int i = 0; i < Recipients_To.length; i++) {
try {
message.setRecipients(Message.RecipientType.TO, Recipients_To[i].toString());
Transport.send(message);
} catch (Exception exp) {
//Log your exception here or do whatever you want to happen in case of exception
}
}
}

Related

IMAP / Jakarta Mail / Unexpected delete flag

I have developed an application that monitors a mailbox and processes certain messages, which are identified by containing a specific keyword in the message subject. When such a message is received, it is deleted from the mailbox and triggers local processing. The code roughly looks like this:
public void process() {
// Create properties
Properties properties = new Properties();
properties.put("mail.imap.host", host);
properties.put("mail.imap.port", port);
properties.put("mail.imap.socketFactory.port", port);
properties.put("mail.imap.partialfetch", "false");
properties.put("mail.imap.fetchsize", 36700160);
// Open
Session session = Session.getInstance(properties);
Store store = session.getStore("imap");
store.connect(emailAddress, password);
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_WRITE);
// Count relevant messages
int count = 0;
try {
// List messages
for (Message message : folder.getMessages()) {
String subject = message.getSubject();
if (subject.contains(keyword)) {
count++;
message.setFlag(Flag.DELETED, true);
// Do some local processing
}
}
} catch (MessagingException e) {
// Log and ignore
} finally {
// Expunge and close if a message was marked deleted
try {
if (count > 0) {
folder.close(true);
}
store.close();
} catch (MessagingException e) {
// Log and ignore
}
}
}
The problem is that some messages that should be processed are never processed. When activating the log on Jakarta mail (log com.sun.mail) I can see that the delete flag is being set for some messages and they are removed before they can be read by the method sketched above (which I see in the application log). As no other client is connected to the mailbox, I believe that my code might be the problem.
The problem only occurs irregularly when the application runs for several hours, so I am not able to provide a minimal example that can be used to reproduce the issue. My question is more of a general nature: has anyone also observed this behaviour when processing messages in a mailbox via IMAP with Jakarte Mail or with any other Email-API or protocol? Do you have any hints what the underlying issue might be? Do you see any issue with the pseudocode shown above?
Any help is very appreciated!
I found a solution which solved the problem:
I did not close the folder and the store object in all cases after a receiving cycle:
If messages were actually received the folder was always closed with folder.close(true).
Additionally I ensured now that in all cases (also exceptions) a method close() is called which contains:
if (folder != null && folder.isOpen()) {
folder.close(false);
}
if (store != null && store.isConnected()) {
store.close();
}
So far the issue did not occur again

How to handle cause by Exception in a good Java way

I have some code in try-catch and in that code I am calling web service.On web service I have set timeout.
I have two web service call one taking no time its working fine and another one taking long to respond problem is not that but because of the time out it should throw SocketTimeoutException but its throwing PrivilegedActionException and after a long stack stace its showing cause by SocketTimeoutException.
I have intentionally put service call time very short to get SocketTimeoutException but its giving me PrivilegedActionException as a primary Exception.
I want to catch SocketTimeoutException and I'm not able to catch PrivilegedActionException becuase at the code level its showing PrivilegedActionException has not been thrown by this try catch.
I have written below code for achieve my goal but it's not working
try {
//some code here for service call
}catch(SocketTimeoutException e)
{
//not able to come here even though cause of the PrivilegedActionException is SocketTimeoutException
}
catch(Exception e)
{
//directly coming here OF COURSE
}
stacktrace:
java.security.PrivilegedActionException: com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Message send failed
com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: java.security.PrivilegedActionException: com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Message send failed
you can catch PrivilegedActionException, and call getCause to get SocketTimeoutException. Maybe a while loop is needed if SocketTimeoutException is not a direct cause.
try{
}catch(PrivilegedActionException e){
Throwable tmp = e;
while(tmp != null){
if(tmp instanceof SocketTimeoutException){
SocketTimeoutException cause = (SocketTimeoutException) tmp;
//Do what you need to do here.
break;
}
tmp = tmp.getCause();
}
}
Temporary solution:
catch(Exception e){
if(e instanceof PrivilegedActionException){
//while loop here
}
}
Its better that you define your own Exception class and perform operations which are required.
Just make sure before throwing the exception you release all the resources which you have been using in your program.

Can't detect disconnect without extra readLine() loop

I am developing a program that uses sockets and currently I have a function in my code that checks for a heartbeat from the client every second.
private void userLoop() { // checks for incoming data from client
Timer t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
try {
socketIn.read(); // check for heartbeat from client
String userInput;
while ((userInput = br.readLine()) != null) {
}
} catch (Exception e) {
ControlPanel.model.removeElement(getUsername());
ControlPanel.append(getUsername() + " has disconnected.");
}
}
}, 1000);
}
When a client closes the game via the X button, shutting off their computer, logging out, whatever it may be, I get the message "'username' has disconnected". This is exactly what I want, however, it only works with the while loop in the code. The while loop essentially does nothing and I have no idea why it doesn't work with out.
If I remove the while loop and I disconnect using my client nothing gets printed out server sided.
String userInput;
while ((userInput = br.readLine()) != null) {
}
The above is essentially the dead code that does nothing but without it my program doesn't work the way it should..
Why is the code needed and how can I remove it and still make my program work correctly?
In this case, your while loop is essentially stalling your program until you no longer receive an input string. It's not dead code; it is just your way of installing a wait.
Otherwise, based on my understanding in the Timer class, it only waits one second, which might be too short of a timespan for what you're waiting to capture.
I fixed my problem by changing everything in the try block with
br.readLine();
There's a saying I've heard about exception handling: "Exceptions should only be used for exceptional situations." A client disconnecting from a server is not exceptional.
Now that I have that off my chest, let's move on. According to this other question,
socket.getInputSteam.read() does not throw when I close the socket from the client
it sounds like the read call won't throw if you're closing things properly on the client side.
The problem is that when the remote socket is closed, read() does not throw an Exception, it just returns -1 to signal the end of the stream.
The following should work without needing to call readLine():
try {
int ret = socketIn.read(); // check for heartbeat from client
if (ret == -1) {
// Remote side closed gracefully
clientDisconnected();
}
} catch (SocketTimeoutException e) {
// Timeout -- handle as required
handleTimeout();
} catch (IOException e) {
// Connection lost due to I/O error
clientDisconnected()
}

Download only email subject in JavaMail & imaps

I'm trying to download only subject of emails, because it should take less time (downloading ~10 emails with photos take about 10 min :/).
Code that I'm now using is:
try {
Store store = session.getStore("imaps");
store.connect(...);
Folder folder = store.getFolder(folderName);
folder.open(Folder.READ_ONLY);
message = folder.getMessages();
for (Message m : message) {
System.out.println(m.getSubject());
}
folder.close(false);
store.close();
} catch (MessagingException e) {
...
} catch (IOException e) {
...
}
it seems to me that you should look into prefetching the messages with:
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
fp.add("Subject");
folder.fetch(message, fp);
What you're doing will download the entire message envelope (but not the entire message), which includes the subject and the recipients. That's usually pretty cheap to download. If you really want only the subject because you're never going to look at the other information, you need to deal with the raw header using something like this:
String rawvalue = msg.getHeader("Subject", null);
if (rawvalue == null)
return null;
try {
return MimeUtility.decodeText(MimeUtility.unfold(rawvalue));
} catch (UnsupportedEncodingException ex) {
return rawvalue;
}
The folder.fetch call described in the other answer will allow you to prefetch all the Subject headers in one operation, instead of fetching each one as you process that message. You can also prefetch the entire envelope if you decide that's what you want; see the javadocs for details.

How to download only new emails from imap?

I have an application that is used to archive emails using imap. Also in this application are many imap accounts that need to be archived.
In this moment from time to time the application connects to imap accounts and download only new emails. My issue is that every time when it connects to an imap account it verifies all emails from all folders and downloads only emails that aren't downloaded yet (I store Message-ID for all emails and download only emails that have an Message-ID that is not stored).
So I want to know if there is an alternative for this, because it takes some time to verify all emails (for 10-20K it takes 2-5 minutes).
I use JavaMail API to connect to imap accounts.
The javadoc helps:
IMAPFolder provides the methods:
getMessagesByUID(long start, long end) and
getUID(Message message)
With getUID() you can get the UID of the last message you already have downloaded. With getMessagesByUID you can define this last message you have downloaded as start-range and look with the method getUIDNext() to find the last message which would be the end of the range.
check only the headers and when you reach a known (the last known), bail out:
for instance (i feel extra nice today) and that's an except from real production code (some parts were cut, so it might not compile, state.processed is some set preferrably LinkedHashMap surrogate [keySet()] (and w/ some max boundary boolean removeEldestEntry())
try {
store = mailSession.getStore("imap");
try {
store.connect();
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_ONLY);
int count = folder.getMessageCount();
for(int localProc=0, chunk=49;localProc<10 && count>0; count -=chunk+1){
Message messages[] = folder.getMessages(Math.max(count-chunk, 1), count);
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
fp.add("Message-ID");
//add more headers, if need be
folder.fetch(messages,fp);
for (int i=messages.length;--i>=0;) {
//can check abort request here
Message message = messages[i];
String msgId = getHeader(message,"Message-ID");
if (msgId!=null && !state.processed.add(msgId)){
if (++localProc>=10){
break;
}
continue;
}
///process here, catch exception, etc..
}
}
folder.close(false);
} catch (MessagingException e) {
logger.log(Level.SEVERE, "Mail messaging exception", e);
}
} catch (NoSuchProviderException e) {
logger.log(Level.SEVERE, "No mail provider", e);
}
if(store != null) {
try {
store.close();
} catch (MessagingException e) {}
}
Filter on the SEEN flag. This flag is intended for finding new messages. The one Caveat is that if your user is using multiple readers, then it may have been seen using another reader.
message-Id which comes as part of the header is always unique even if u set it manually .i have tested it with gamil and racksoace.

Categories