Can I perform a search on mail server in Java? - java

I am trying to perform a search of my gmail using Java. With JavaMail I can do a message by message search like so:
Properties props = System.getProperties();
props.setProperty("mail.store.protocol", "imaps");
Session session = Session.getDefaultInstance(props, null);
Store store = session.getStore("imaps");
store.connect("imap.gmail.com", "myUsername", "myPassword");
Folder inbox = store.getFolder("Inbox");
inbox.open(Folder.READ_ONLY);
SearchTerm term = new SearchTerm() {
#Override
public boolean match(Message mess) {
try {
return mess.getContent().toString().toLowerCase().indexOf("boston") != -1;
} catch (IOException ex) {
Logger.getLogger(JavaMailTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (MessagingException ex) {
Logger.getLogger(JavaMailTest.class.getName()).log(Level.SEVERE, null, ex);
}
return false;
}
};
Message[] searchResults = inbox.search(term);
for(Message m:searchResults)
System.out.println("MATCHED: " + m.getFrom()[0]);
But this requires downloading each message. Of course I can cache all the results, but this becomes a storage concern with large gmail boxes and also would be very slow (I can only imagine how long it would take to search through gigabytes of text...).
So my question is, is there a way of searching through mail on the server, a la gmail's search field? Maybe through Microsoft Exchange?
Hours of Googling has turned up nothing.

You can let the server do the search for you, with the appropriate IMAP command. The SEARCH command will only get you so far, what you probably need is the SORT command. SORT isn't implemented in JavaMail but the documentation shows how you can implement it yourself:
http://java.sun.com/products/javamail/javadocs/com/sun/mail/imap/IMAPFolder.html#doCommand(com.sun.mail.imap.IMAPFolder.ProtocolCommand)
(I couldn't figure out how to link to a URL with parentheses)

Connect to the Exchange IMAP store and use javax.mail.search.SearchTerm

Related

Unable to retrieve emails from Gmail using Java

I am trying to write a simple program in Java, in order to check my mailbox and get whatever email is in the inbox.
I have read various tutorials and watched a video in youtube and I found out that most people do something similar to this
So the I have taken the code found there:
import java.util.Properties;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;
public class CheckingMails {
public static void check(String host, String storeType, String user,
String password)
{
try {
//create properties field
Properties properties = new Properties();
properties.put("mail.pop3.host", host);
properties.put("mail.pop3.port", "995");
properties.put("mail.pop3.starttls.enable", "true");
Session emailSession = Session.getDefaultInstance(properties);
//create the POP3 store object and connect with the pop server
Store store = emailSession.getStore("pop3");
store.connect(host, user, password);
//create the folder object and open it
Folder emailFolder = store.getFolder("INBOX");
emailFolder.open(Folder.READ_ONLY);
// retrieve the messages from the folder in an array and print it
Message[] messages = emailFolder.getMessages();
System.out.println("messages.length---" + messages.length);
for (int i = 0, n = messages.length; i < n; i++) {
Message message = messages[i];
System.out.println("---------------------------------");
System.out.println("Email Number " + (i + 1));
System.out.println("Subject: " + message.getSubject());
System.out.println("From: " + message.getFrom()[0]);
System.out.println("Text: " + message.getContent().toString());
}
//close the store and folder objects
emailFolder.close(false);
store.close();
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String host = "pop.gmail.com";// change accordingly
String mailStoreType = "pop3";
String username = "giannisthedrummer2#gmail.com";// change accordingly
String password = "********";// change accordingly
check(host, mailStoreType, username, password);
}
}
But I can't get my mails. Instead this error appears:
javax.mail.AuthenticationFailedException: EOF on socket
at com.sun.mail.pop3.POP3Store.protocolConnect(POP3Store.java:104)
at javax.mail.Service.connect(Service.java:233)
at javax.mail.Service.connect(Service.java:134)
at CheckingMails.check(CheckingMails.java:29)
at CheckingMails.main(CheckingMails.java:69)
I have enabled the POP and IMAP accesibility features on my email, as well as enabled less secure connections.
I downloaded the necessary .jar files from mail.jar and activation.jar
After looking around a bit, I found out that the issue probably is coming from Google's side, meaning that the authentication is going worng. The password and the name is correct (I have checked that multiple times). I have enabled both IMAP and POP connections and I have allowed less secure connections, but still I get an javax.mail.AuthenticationFailedException error.
Any ideas why is this happening?
You're connecting on the SSL port but not enabling SSL. Follow the Gmail instructions in the JavaMail FAQ. Get rid of the port setting and set mail.pop3.ssl.enable.
And make sure you understand the limitations of pop3 vs. imap.
do below change to your Gmail account to access it from outside
Login to Gmail.
Access the URL as https://www.google.com/settings/security/lesssecureapps
Select "Turn on"
For the people that will struggle in the future in the same way I did:
After applying the suggestion from Bill Shannon, I got another error,which I found out that it was coming due to the fact that I hadn't configure the ssl certificates properly. Since I have little to no clue about those, I was searching around the internet to find
Properties properties = new Properties();
properties.put("mail.imap.host", host);
properties.put("mail.imap.user", user);
properties.setProperty("mail.imap.ssl.enable", "true");
properties.put("mail.imap.ssl.trust", "*");
I changed the pop3 protocol to IMAP, because the later allows me to perform more tasks, but for the sole purpose of retrieving my emails both work in the same way.
The last line, in my understanding will accept any certificate, which probably is not the right way to go about it, but at the moment I don't know which one is the correct one.
Thank you all for your help.
****** It is important that the user, enables the POP3/IMAP connections in their accounts and also turn on the less secure applications, as it was stated previously. ******

How to read mail with java mail API (String cannot be cast to Multipart)

I am trying to write a simple code that will read messages from gmail inbox.
I have found some examples, but non of them is working.
Most promising is code I've found on CompilatimEerror.com, BUT whatever I try I get this error:
java.lang.ClassCastException: java.lang.String cannot be cast to javax.mail.Multipart
Here is my code:
import java.util.*;
import javax.mail.*;
public class ReadingEmail {
public static void main(String[] args) {
Properties props = new Properties();
props.setProperty("mail.store.protocol", "imaps");
try {
Session session = Session.getInstance(props, null);
Store store = session.getStore();
store.connect("imap.gmail.com", "yourEmailId#gmail.com","password");
Folder inbox = store.getFolder("INBOX");
inbox.open(Folder.READ_ONLY);
Message msg = inbox.getMessage(inbox.getMessageCount());
Address[] in = msg.getFrom();
for (Address address : in) {
System.out.println("FROM:" + address.toString());
}
Multipart mp = (Multipart) msg.getContent(); // here it breaks
BodyPart bp = mp.getBodyPart(0);
System.out.println("SENT DATE:" + msg.getSentDate());
System.out.println("SUBJECT:" + msg.getSubject());
System.out.println("CONTENT:" + bp.getContent());
} catch (Exception mex) {
mex.printStackTrace();
}
}
}
There is no connection error, as it gets the subject, date, and all this stuff, but the email body is a mystery. There will be no attachments, I will get only simple mails(this is a part of greater project)
What I am looking for is to read the unread mail (and then delete this message, so the inbox will be permanently empty(spam will be deleted manually)).
I lack knowledge about web programing/structures, and all that pop's, imaps and stuff is a blank space.
Also keep in mind that I am a novice programmer and this is the first time that I go outside of my computer with my code unfortunately straight into the problems of protocols / authentication / getting things from internet.
I went through a lot of pages, but never found an explanation that would allow me to create it myself...
Are you related to this guy?
The JavaMail FAQ has pointers to lots of helpful information, including the JavaMail project page, sample code, etc. You'll also find pointers to some useful background material and tutorials here.

Google app engine not sending mail despite calls appearing in Quota details

I have spent the weekend playing with Google App Engine and Google Web Toolkit and have got along pretty well and built a simple app.
The stumbling block seems to be sending e-mails. My code is:
private void sendOffenderMail( OffenceDetails offence )
{
if( offence.email == null || offence.email.equals("") )
{
return;
}
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
String msgBody = "You have been added to the list";
if( offence.notes != null && !offence.notes.equals( "" ) )
{
msgBody += "\n\nThe following notes were included:\n\n" + offence.notes;
}
Message msg = new MimeMessage(session);
try {
msg.setFrom( new InternetAddress(<gmail account belonging to project viewer>, "List Admin") );
msg.addRecipient(
Message.RecipientType.TO,
new InternetAddress (offence.email, offence.name )
);
msg.setSubject("You've been added to the list...");
msg.setText(msgBody);
Transport.send(msg);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
}
}
When I run this on the development server logs get printed out in the console about the mail that would have been sent.
When I deploy to app engine and try there nothing happens, I don't get any mail.
If I look in to the quota details I can see mail api calls there. If I look at the logs there are no errors (but I can't see and of my logs in there...).
It seems odd that I have essentially been charged for sending this (quota used up) but no mails actually got through.
I HAVE checked my spam folder BTW.
It seems that gmail account that you use is a Project Viewer. The docs state that it should be a Developer.
In the end I just used the e-mail address of the currently logged in user - which is always an admin as you can only get to this part of the app if you're an admin.
I could not get it to work using a hardwired address belonging to one of the admins.

javamail mark gmail message as read

Note: added after answer:
Thanks.. Yeah I had tried the Flag.SEEN to true and saveChanges.. I also had read getContent marks it read. I tried using it in the for statement that loops through the messages. But I got the messages again from the folder anyways in the next loop. I was assuming the folder was live, so grabbing the content, then grabbing the messages again from the folder with the filter to not get any seen should work, but I was still getting the same message. I could try closing the folder and reopen as a test to see if it's marked. Also if I go over to my client and click the message, then my code stops seeing it even in the loop, so I was hoping to do the same in the code.
original:
I'm using javamail to get email from a gmail account, it's working great, when I get the message I'd like to mark it as read, can anyone give me some direction? Here is my current code:
Properties props = System.getProperties();
props.setProperty("mail.store.protocol", "imaps");
try {
Session session = Session.getDefaultInstance(props, null);
Store store = session.getStore("imaps");
store.connect("imap.gmail.com", eUserName, ePassWord);
// Get folder
Folder folder = store.getFolder("INBOX");
if (folder == null || !folder.exists()) {
return null;
}
folder.open(Folder.READ_ONLY);
// Only pull unread
FlagTerm ft = new FlagTerm(new Flags(Flags.Flag.SEEN), false);
Message messages[]; // = folder.search(ft);
for(int x = 0; x < timeOutInSeconds; x++) {
log.reportMessage("looking for emails");
try {
folder.getMessages();
messages = folder.search(ft);
if (messages.length > 0) {
for (Message message : messages) {
//log.reportMessage("found message: should not see again, marking read");
// want to mark as read
}
}
Thread.sleep(1000);
}
catch(Exception ex) {
}
}
// Close connection
folder.close(false);
store.close();
return null;
}
catch (NoSuchProviderException ex) {
return null;
}
catch (MessagingException ex) {
return null;
}
}
First of all, you can't mark a message as read if you are using a POP3 server - the POP3 protocol doesn't support that. However, the IMAP v4 protocol does.
You might think the way to do this is to get the message, set the Flags.Flag.SEEN flag to true, and then call message.saveChanges(). Oddly, this is not the case.
Instead, the JavaMail API Design Specification, Chapter 4, section "The Flags Class" states that the SEEN flag is implicitly set when the contents of a message are retrieved. So, to mark a message as read, you can use the following code:
myImapFolder.open(Folder.READ_WRITE);
myImapFolder.getMessage(myMsgID).getContent();
myImapFolder.close(false);
Or another way is to use the MimeMessage copy constructor, ie:
MimeMessage source = (MimeMessage) folder.getMessage(1)
MimeMessage copy = new MimeMessage(source);
When you construct the copy, the seen flag is implicitly set for the message referred to by source.
One liner that will do it WITHOUT downloading the entire message:
single message:
folder.setFlags(new Message[] {message}, new Flags(Flags.Flag.SEEN), true);
all messages:
folder.setFlags(messages, new Flags(Flags.Flag.SEEN), true);
Other methods of calling getContent() or creating a copy with new MimeMessage(original) cause the client to download the entire message, and creates a huge performance hit.
Note that the inbox must be opened for READ_WRITE:
folder.open(Folder.READ_WRITE);
Well this post is old but the easiest solution hasnĀ“t been posted yet.
You are accessing the Message.
message.setFlag(Flag.SEEN, true);
for (Message message : messages) {
message.setFlag(Flags.Flag.SEEN,true);
}
and change the below line
folder.open(Folder.READ_ONLY);
to this
folder.open(Folder.READ_WRITE);
You may also consider having a public static int max_message_number, and storing in it the message[i].getMessageNumber(); as soon as you read a message. Then before reading any message just check if the max_message_number < message[i].getmessageNumber(). If true then don't print this message (as it has been already read)
message.setFlag( Flag.SEEN,true ) give "cannot find symbol"
message.setFlag( Flags.Flag.SEEN,true ) seems good.
If you are using a for loop to read or check a mail one by one, the code can be as follows to mark a gmail message as read:
Message[] unreadMessages = inbox.search(new FlagTerm(new Flags(Flag.SEEN), false));
for (int q = 0; q < unreadMessages.length; q++) {
unreadMessages[q].setFlag(Flag.SEEN, true);
}
What this code does is that it makes it unread one by one.
And also folder/inbox needs to be READ_WRITE, instead of READ_ONLY:
folder.open(Folder.READ_WRITE);
You can also try
head over to the gmail settings > Forwarding and POP/IMAP
from the dropdown of When messages are accessed with POP
select mark Gmail's copy as read and save the changes
To mark the mail as read, you just have to call the mailmessage.getContent() method.
Whether you use IMAP or POP, calling that method on a specific mail mark it as Read
The easiest way to do that is set the folder to be read or written into or from. Means like this...
Folder inbox = null;
inbox.open(Folder.READ_WRITE);
the Folder class should be imported.

Javamail performance

I've been using javamail to retrieve mails from IMAP server (currently GMail). Javamail retrieves list of messages (only ids) in a particular folder from server very fast, but when I actually fetch message (only envelop not even contents) it takes around 1 to 2 seconds for each message. What are the techniques should be used for fast retrieval?
here is my code:
try {
IMAPStore store = null;
if(store!=null&&store.isConnected())return;
Properties props = System.getProperties();
Session sessionIMAP = Session.getInstance(props, null);
try {
store = (IMAPStore) sessionIMAP.getStore("imaps");
store.connect("imap.gmail.com",993,"username#gmail.com","password");
} catch (Exception e) {
e.printStackTrace();
}
IMAPFolder folder = (IMAPFolder) store.getFolder("INBOX");
folder.open(Folder.READ_ONLY);
System.out.println("start");
Message[] msgs = folder.getMessages(1,10);
long ftime = System.currentTimeMillis();
FetchProfile fp=new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
folder.fetch(msgs, fp);
long time = System.currentTimeMillis();
System.out.println("fetch: "+(time-ftime));
for (Message message : msgs) {
System.out.println(message.getSubject());
Address[] from = message.getFrom();
for (Address address : from) {
System.out.println(address);
}
Address[] recipients = message.getAllRecipients();
for (Address address : recipients) {
System.out.println(address);
}
}
long newTime = System.currentTimeMillis();
System.out.println("convert: "+(newTime-time));
}catch (Exception e) {
e.printStackTrace();
}
}
I believe that Gmail throttles the IMAP message reads to one every second or so. You might be able to speed it up with multiple IMAP connections.
Please set the Property mail.imap.fetchsize with the required size. the default is 16k.
In case you increase the size of this property, retrieve speed will go up.
props.put("mail.imap.fetchsize", "3000000");
Note that if you're using the "imaps" protocol to access IMAP over SSL, all the properties would be named "mail.imaps.*".
Good Luck.
Yaniv
I'm not sure if this is a Javamail issue as much as it may be a Gmail issue. I have an application that retrieves mail from a number of sources, including Gmail, and Gmail is definitely the slowest. The Javamail api is pretty straightforward, but it would be hard to make suggestions without seeing what you are currently doing.
I'm running into the same thing. After profiling, I noticed that getBody was being called every time I tried to do a message.getFrom() like you are, even though I was only accessing fields that should be covered by the Envelope flag. See https://java.net/projects/javamail/forums/forum/topics/107956-gimap-efficiency-when-only-reading-headers

Categories

Resources