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.

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;

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.

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;

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:

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;

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