Fetching Gmails Via Mailcore 2: Thread ID vs Message ID vs UID
Asked Answered
U

2

12

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.

Uncertain answered 13/1, 2014 at 16:23 Comment(0)
U
9

After opening an issue with Mailcore and a bit of research I have found the answers to my own questions.

First, my above assumptions about UID, gmailMessageID and gmailThreadID are correct. The confusion was in my looking at the Gmail conversation view of my email account on the web, and expecting my Mailcore fetch to match it. This does not happen because the conversation view, as the name implies, stitches together ALL messages of a conversation, even those that were replies to an incoming message in the inbox - ordinarily such messages would be found in the 'sent' or 'all mail' folder. In other words, what is fetched from Mailcore looks incomplete only because it is fetching what is ACTUALLY in your inbox (or whatever folder you are fetching messages from). This does NOT include replies to incoming messages. In order to include such messages (i.e. to re-create Gmail's conversation view) I understand that one must fetch sent messages from 'all mail' (or I suppose 'sent' mail) by doing a search operation using the gmailThreadID of the message of interest.

Switching the conversation view to 'off' for my Gmail account on the web while testing my Mailcore fetch operations makes testing much clearer.

Uncertain answered 13/1, 2014 at 22:57 Comment(4)
Tell me some idea about i want to get all mail conversation in single mail. Now i am getting each and every conversation in separate mail.Laundress
Its been a while since I've done this, but to my recollection you will get all the messages separately, then on your side you must join together which ever messages have the same threadID to re-create a conversation.Uncertain
Thanks for for your comments. Can you give me sample code. It will better for me.Laundress
Hi @user1697845 I m going to using same logic, but when I try to use like NSLog(@"thread ID %llu",message.gmailThreadID); then always get 0. please let me know where I m wrong.Pessa
P
1

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);
Pessa answered 4/8, 2017 at 4:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.