Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fetching Gmails Via Mailcore 2: Thread ID vs Message ID vs UID

I have an iPad application that allows users to access their Gmail accounts using Mailcore2. I thought I had an understanding of the difference between Gmail's Thread Id, Message ID and UID until I looked closely at what Mailcore2 is returning to me when I perform a message fetch operation. I am hoping someone can clarify my confusion.

Here is what I think I know from the Gmail docs:

1) A thread ID groups together messages (which have their own message IDs and UIDs) that are part of the same conversation

2) A UID is specific to a message and is unique only to the folder which contains it

3) A message ID is specific to a message and is unique across all folders of an account

I am also making the following assumptions:

1) A thread has a thread ID and is a collection of messages. A thread does not have a message ID or a UID.

2) A message has a message ID, UID and thread ID (even if it is the only message in a thread)

3) Fetching messages by UID fetches MESSAGES which have a UID that falls in the requested range of UIDs.

4) Messages that belong to the same thread will have different UIDs and message IDs but the same Thread ID.

Ok, so assuming that the above is correct, I would think that during a typical fetch of messages in Mailcore2 by UID, I would receive an array of emails, and from those emails I could look at their thread ID, for example and reconstruct threads on the client side. However, I seem to get back threads rather than emails. Additionally, each thread I get does not necessarily contain all its 'child' messages.

So for example, if I have two threads in my inbox, each containing five messages, Mailcore returns to me an array of 2 "emails" in the form of MCOIMAPMessages. And each "email" has one thread ID, one message ID and one UID. So I am not sure how to access contained emails on these two threads. I see that there is a references array... but inspecting this object doesn't reveal anything useful. When I log the contents of each thread, I get only part of the contents - say 4 out of the 5 messages on the thread. Not sure if this is Mailcore or an error in my saving process due to my incomplete understanding of how this is all working.

Here is my code to fetch messages:

//create fetch operation to get first (10) messages in folder (first fetch is done by sequence number, subsequent fetches are done by UID

uint64_t location = MAX([info messageCount] - DefaultPageSize + 1, 1);
uint64_t size = serverMessageCount < DefaultPageSize ? serverMessageCount - 1 : DefaultPageSize - 1;

MCOIndexSet *numbers = [MCOIndexSet indexSetWithRange:MCORangeMake(location, size)];

MCOIMAPMessagesRequestKind kind =  MCOIMAPMessagesRequestKindUid |
      MCOIMAPMessagesRequestKindFullHeaders |
      MCOIMAPMessagesRequestKindFlags |
      MCOIMAPMessagesRequestKindHeaders |
      MCOIMAPMessagesRequestKindInternalDate;

if ([capabilities containsIndex:MCOIMAPCapabilityGmail]) {
        kind |= MCOIMAPMessagesRequestKindGmailLabels | MCOIMAPMessagesRequestKindGmailThreadID | MCOIMAPMessagesRequestKindGmailMessageID;
        self.gmailCapability = YES;
      }

fetchLatestEmails ([self.imapSession fetchMessagesByNumberOperationWithFolder:folder.folderId requestKind:kind numbers:numbers]);

//perform fetch

void (^fetchLatestEmails)(MCOIMAPFetchMessagesOperation *) = ^(MCOIMAPFetchMessagesOperation *fetchOperation) {

  [fetchOperation start:^(NSError *error, NSArray *emails,  MCOIndexSet *vanishedMessages) {

    if (nil != error) {
      failure(error);
      NSLog(@"the fetch error is %@", error);
      return;
    }

    [self.dataManager performBatchedChanges:^{
      if ([emails count] !=0) {

        MCOIndexSet *savedThreadIds = [[MCOIndexSet alloc]init];

        for (MCOIMAPMessage *email in emails) {

           //do stuff with emails

          Thread *thread = [self.dataManager fetchOrInsertNewThreadForFolder:folder threadId:email.gmailThreadID ?: email.gmailMessageID ?: email.uid error:nil];

          if (nil != thread) {

            [savedThreadIds addIndex:thread.threadId];

            [self.dataManager updateOrInsertNewEmailForThread:thread uid:email.uid messageId:email.gmailMessageID date:email.header.receivedDate subject:email.header.subject from:email.header.from.mailbox to:[email.header.to valueForKey:@"mailbox"] cc:[email.header.cc valueForKey:@"mailbox"] labels:labels flags:flags error:nil];

          }

          if (nil != error) {
            failure(error);
            return;
          }

        }

        [savedThreadIds enumerateIndexes:^(uint64_t threadId) {
          [self.dataManager updateFlagsForThreadWithThreadId:threadId inFolder:folder];
        }];

      }

      NSError *folderUpdateError;
      [self.dataManager updateFolder:folder withMessageCount:serverMessageCount error:&folderUpdateError];

    } error:&error];

    if (nil == error) {

      [self refreshFolder:folder success:^{
        success();
      }failure:^(NSError *error) {

      }];

    } else {
      failure(error);
    }
  }];
};

Clearly something is amiss here in terms of my understanding of either Gmail or Mailcore2. If anyone can point out my misunderstanding I would appreciate it.

like image 772
jac300 Avatar asked Jan 13 '14 16:01

jac300


1 Answers

Found the answer for getting gmailThreadID we need to add MCOIMAPMessagesRequestKindGmailThreadID. in Fetch request like below example.

   MCOIMAPMessagesRequestKind requestKind = (MCOIMAPMessagesRequestKind)
    (MCOIMAPMessagesRequestKindHeaders | MCOIMAPMessagesRequestKindStructure |
     MCOIMAPMessagesRequestKindInternalDate | MCOIMAPMessagesRequestKindHeaderSubject |
     MCOIMAPMessagesRequestKindFlags | MCOIMAPMessagesRequestKindGmailThreadID);
like image 71
Deepak Bhati Avatar answered Oct 08 '22 08:10

Deepak Bhati