2
votes

I work on university project in java. I have to download attachments from new emails using GMAIL API.

I successfully connected to gmail account using OAuth 2.0 authorization.

private static final List<String> SCOPES = Collections.singletonList(GmailScopes.GMAIL_READONLY);

I tried to get unseen mails using

ListMessagesResponse listMessageResponse = service.users().messages().list(user).setQ("is:unseen").execute();

listMessageResponse is not null but when I call method .getResultSizeEstimate() it returns 0 also I tried to convert listMessageResponse to List < Message > (I guess this is more usable) using

List<Message> list = listMessageResponse.getMessages();

But list launches NullPointerException

Then tried to get each attachment with

for(Message m : list) {
            List<MessagePart> part = m.getPayload().getParts();
            for(MessagePart p: part) {
                if(p.getFilename()!=null && p.getFilename().length()>0) {
                    System.out.println(p.getFilename()); // Just to check attachment filename
                }
            }
        }

Is my approach correct (if not how to fix it) and how should I download those attachments.

EDIT 1:

Fixed q parameter, I mistakenly wrote is:unseen instead of is:unread. Now app reaches unread mails successfully. (For example there was two unread mails and both successfully reached, I can get theirs IDs easy).

Now this part trows NullPointerException

List<MessagePart> part = m.getPayload().getParts();

Both messages have attachments and m is not null (I get ID with .getID())

Any ideas how to overcome this and download attachment?

EDIT 2:

Attachments Downloading part

for(MessagePart p : parts) {

            if ((p.getFilename() != null && p.getFilename().length() > 0)) {
                String filename = p.getFilename();
                String attId = p.getBody().getAttachmentId();
                MessagePartBody attachPart;
                FileOutputStream fileOutFile = null;
                try { 
                   attachPart = service.users().messages().attachments().get("me", p.getPartId(), attId).execute();
                   byte[] fileByteArray = Base64.decodeBase64(attachPart.getData());


                   fileOutFile = new FileOutputStream(filename); // Or any other dir
                   fileOutFile.write(fileByteArray);
                   fileOutFile.close();
                }catch (IOException e) {
                    System.out.println("IO Exception processing attachment: " + filename);
                } finally {
                   if (fileOutFile != null) {
                      try {
                         fileOutFile.close();
                      } catch (IOException e) {
                         // probably doesn't matter
                      }
                   }
                }
            }
        }

Downloading working like charm, tested app with different type of emails. Only thing left is to change label of unread message (that was reached by app) to read. Any tips how to do it?

And one tiny question: I want this app to fetch mails on every 10 minutes using TimerTask abstract class. Is there need for manual "closing" of connection with gmail or that's done automatically after run() method iteration ends?

 @Override
 public void run(){

 // Some fancy code

 service.close(); // Something like that if even exists
 }
1
You have a custom label called unseen? Remember Response wont be null its always going to return you a response object. how ever it sounds like there are no results for your custom label.DaImTo
I made silly mistake there I wanted to write unread but wrote unseen.Herien Wolf
@BogosavCvetkovic I updated my answer accordingly, please let me know whether that works for you.Iamblichus
@BogosavCvetkovic Since your original question got solved, I'd suggest to post a new question with your current problem, and please consider accepting the answer I provided, since that's fundamental to sharing knowledge between users in SO. Also, of course, before posting a new question, please do some research on the subject of changing labels, and only post a question if you encounter problems you cannot solve.Iamblichus
Users.messages: modify and Class Gmail.Users.Messages.Modify could be good places to start your research on label changing.Iamblichus

1 Answers

1
votes

I don't think ListMessagesResponse ever becomes null. Even if there are no messages that match your query, at least resultSizeEstimate will get populated in the resulting response: see Users.messages: list > Response.

I think you are using the correct approach, just that there is no message that matches your query. Actually, I never saw is:unseen before. Did you mean is:unread instead?

Update:

When using Users.messages: list only the id and the threadId of each message is populated, so you cannot access the message payload. In order to get the full message resource, you have to use Users.messages: get instead, as you can see in the referenced link:

Note that each message resource contains only an id and a threadId. Additional message details can be fetched using the messages.get method.

So in this case, after getting the list of messages, you have to iterate through the list, and do the following for each message in the list:

  • Get the message id via m.getId().
  • Once you have retrieved the message id, use it to call Gmail.Users.Messages.Get and get the full message resource. The retrieved message should have all fields populated, including payload, and you should be able to access the corresponding attachments.

Code sample:

List<Message> list = listMessageResponse.getMessages();
for(Message m : list) {
  Message message = service.users().messages().get(user, m.getId()).execute();
  List<MessagePart> part = message.getPayload().getParts();
  // Rest of code
}

Reference: