Skip to main content
Table of Contents

Labels and messages

Gmail organizes mail with labels rather than a folder hierarchy — a message can carry several labels at once (its Inbox membership, STARRED, IMPORTANT, and any user-created labels), and TTMSFNCCloudGoogleGmail reads both the account's labels and its messages. Every request is asynchronous — a method returns immediately and the result arrives in a matching On... event, with the retrieved data exposed through a collection property on the component. This chapter covers listing labels, retrieving messages with a Gmail search query, and knowing when a full page of messages is actually ready to read.

Listing labels

GetLabels retrieves the account's labels into the read-only Labels collection, raising OnGetLabels when they are available. Both system labels (INBOX, STARRED, IMPORTANT, …) and user-created labels are returned, distinguished by LabelType.

List Gmail labelsPascalC++
procedure TForm1.ListGmailLabels;
begin
  TMSFNCCloudGoogleGmail1.OnGetLabels := GmailLabelsListed;
  TMSFNCCloudGoogleGmail1.GetLabels;
end;

procedure TForm1.GmailLabelsListed(Sender: TObject;
  const ARequestResult: TTMSFNCCloudBaseRequestResult);
var
  i: Integer;
begin
  if not ARequestResult.Success then
    Exit;

  for i := 0 to TMSFNCCloudGoogleGmail1.Labels.Count - 1 do
    Memo1.Lines.Add(TMSFNCCloudGoogleGmail1.Labels[i].Name
      + ' (' + TMSFNCCloudGoogleGmail1.Labels[i].LabelType + ')');
end;
void __fastcall TForm1::ListGmailLabels()
{
  TMSFNCCloudGoogleGmail1->OnGetLabels = GmailLabelsListed;
  TMSFNCCloudGoogleGmail1->GetLabels();
}

void __fastcall TForm1::GmailLabelsListed(TObject *Sender,
  TTMSFNCCloudBaseRequestResult *ARequestResult)
{
  if (!ARequestResult->Success)
    return;

  for (int i = 0; i < TMSFNCCloudGoogleGmail1->Labels->Count; i++)
    Memo1->Lines->Add(TMSFNCCloudGoogleGmail1->Labels->Items[i]->Name
      + " (" + TMSFNCCloudGoogleGmail1->Labels->Items[i]->LabelType + ")");
}

Retrieving messages

GetMails retrieves messages carrying the given label(s) ('INBOX' by default), with an optional Gmail search AQuery (the same syntax as the Gmail search box, for example has:attachment from:someone@example.com) to further filter the results. AMaxResults caps the page size, and GetNextPage automatically continues fetching subsequent pages until every matching message has been retrieved.

Retrieve Gmail messages with a search queryPascalC++
procedure TForm1.SearchUnreadWithAttachments;
begin
  TMSFNCCloudGoogleGmail1.OnGetMailsComplete := GmailMessagesReady;
  // AQuery uses Gmail's own search syntax.
  TMSFNCCloudGoogleGmail1.GetMails('INBOX', 50, True, 'is:unread has:attachment');
end;

procedure TForm1.GmailMessagesReady(Sender: TObject;
  const ARequestResult: TTMSFNCCloudBaseRequestResult);
var
  i: Integer;
  m: TTMSFNCCloudGoogleGmailMessage;
begin
  if not ARequestResult.Success then
    Exit;

  // Safe to read Mails here: every page and every message detail has loaded.
  for i := 0 to TMSFNCCloudGoogleGmail1.Mails.Count - 1 do
  begin
    m := TMSFNCCloudGoogleGmail1.Mails[i];
    Memo1.Lines.Add(m.Subject + ' - ' + m.From);
  end;
end;
void __fastcall TForm1::SearchUnreadWithAttachments()
{
  TMSFNCCloudGoogleGmail1->OnGetMailsComplete = GmailMessagesReady;
  // AQuery uses Gmail's own search syntax.
  TMSFNCCloudGoogleGmail1->GetMails("INBOX", 50, true, "is:unread has:attachment");
}

void __fastcall TForm1::GmailMessagesReady(TObject *Sender,
  TTMSFNCCloudBaseRequestResult *ARequestResult)
{
  if (!ARequestResult->Success)
    return;

  // Safe to read Mails here: every page and every message detail has loaded.
  for (int i = 0; i < TMSFNCCloudGoogleGmail1->Mails->Count; i++)
  {
    TTMSFNCCloudGoogleGmailMessage *m = TMSFNCCloudGoogleGmail1->Mails->Items[i];
    Memo1->Lines->Add(m->Subject + " - " + m->From);
  }
}

OnGetMails vs OnGetMailsComplete

GetMails does more work behind the scenes than a single list call: for every message ID returned by the list, the component also fetches that message's full details (subject, body, headers, labels). OnGetMails can fire while those per-message detail requests are still in flight, so Mails is not guaranteed to be fully populated yet. Wait for OnGetMailsComplete — which only fires once every page and every message detail has finished loading — before reading Mails for a complete result.

Combining a label listing with a filtered message page

Listing the labels first lets you resolve a label's ID before filtering messages by it — here the labels are listed, and the first user-created label found is used to retrieve its messages:

List labels, then retrieve messages for the first user-created labelPascalC++
procedure TForm1.BrowseLabelsThenMessages;
begin
  TMSFNCCloudGoogleGmail1.OnGetLabels := ListedThenGetMails;
  TMSFNCCloudGoogleGmail1.OnGetMailsComplete := GmailLabelMessagesReady;
  TMSFNCCloudGoogleGmail1.GetLabels;
end;

procedure TForm1.ListedThenGetMails(Sender: TObject;
  const ARequestResult: TTMSFNCCloudBaseRequestResult);
var
  i: Integer;
begin
  if not ARequestResult.Success then
    Exit;

  for i := 0 to TMSFNCCloudGoogleGmail1.Labels.Count - 1 do
  begin
    if TMSFNCCloudGoogleGmail1.Labels[i].LabelType = 'user' then
    begin
      TMSFNCCloudGoogleGmail1.GetMails(TMSFNCCloudGoogleGmail1.Labels[i].ID, 25, True);
      Break;
    end;
  end;
end;

procedure TForm1.GmailLabelMessagesReady(Sender: TObject;
  const ARequestResult: TTMSFNCCloudBaseRequestResult);
var
  i: Integer;
begin
  if ARequestResult.Success then
    for i := 0 to TMSFNCCloudGoogleGmail1.Mails.Count - 1 do
      Memo1.Lines.Add(TMSFNCCloudGoogleGmail1.Mails[i].Subject);
end;
void __fastcall TForm1::BrowseLabelsThenMessages()
{
  TMSFNCCloudGoogleGmail1->OnGetLabels = ListedThenGetMails;
  TMSFNCCloudGoogleGmail1->OnGetMailsComplete = GmailLabelMessagesReady;
  TMSFNCCloudGoogleGmail1->GetLabels();
}

void __fastcall TForm1::ListedThenGetMails(TObject *Sender,
  TTMSFNCCloudBaseRequestResult *ARequestResult)
{
  if (!ARequestResult->Success)
    return;

  for (int i = 0; i < TMSFNCCloudGoogleGmail1->Labels->Count; i++)
  {
    if (TMSFNCCloudGoogleGmail1->Labels->Items[i]->LabelType == "user")
    {
      TMSFNCCloudGoogleGmail1->GetMails(TMSFNCCloudGoogleGmail1->Labels->Items[i]->ID, 25, true);
      break;
    }
  }
}

void __fastcall TForm1::GmailLabelMessagesReady(TObject *Sender,
  TTMSFNCCloudBaseRequestResult *ARequestResult)
{
  if (ARequestResult->Success)
    for (int i = 0; i < TMSFNCCloudGoogleGmail1->Mails->Count; i++)
      Memo1->Lines->Add(TMSFNCCloudGoogleGmail1->Mails->Items[i]->Subject);
}

Common mistakes

  • Reading Mails from OnGetMails instead of OnGetMailsComplete. The collection can still be filling in per-message details at that point; see above.
  • Assuming GetNextPage = True retrieves everything in one event. Pagination still happens behind the scenes across multiple requests; only OnGetMailsComplete signals that all pages have arrived.

See also