Creating a gloda message query

This content covers features introduced in Thunderbird 3

This page describes how to programmatically create a message query using gloda, Thunderbird's global database. See the gloda page for background on the component. See Gloda examples for more code samples.

Creating your first message query...

Import gloda

Gloda's API is exposed in the "Gloda" object that is contributed to your namespace. You can find the file, which includes doxygen markup of sorts, here: https://hg.mozilla.org/comm-central/file/tip/mailnews/db/gloda/modules/gloda.js

Components.utils.import("resource:///modules/gloda/public.js");

Create the query

let query = Gloda.newQuery(Gloda.NOUN_MESSAGE);

Add constraints to the query

Each constraint function takes one or more arguments which are "OR"ed together. So if we had a "color" constraint such as query.color("red", "green", "blue") would mean any of red, green, or blue is okay. Constraints are "AND"ed together. So if we had a "shape" constraint such as query.shape("square") and we combined it with the previous color constraint it would match a red square, a green square, or a blue square.

  • query.involves(identity1, identity2, ...): Add the constraint that the message must "involve" one of the identities provided. An identity is involved if the message was to them, from them, or carbon-copied to them.
  • gloda.from, gloda.to, gloda.cc: Just like gloda.involves, but specific to from/to/cc.
  • gloda.dateRange([lowerDate1, upperDate1], [lowerDate2, upperDate2], ...): Add the constraint that the message date (per the message's Date header) must fall within one of the specified inclusive ranges. The date instances are JavaScript Date instances.
  • query.folder(folder1, folder2, ...): Add the constraint that the message must be found in one of the specified folders. The folder may be a GlodaFolder instance (retrieved via Gloda.getFolderForFolder, which takes an nsIMsgFolder) or an nsIMsgFolder instance.
  • query.conversation(conversation1, conversation2, ...): Add the constraint that the message must belong to one of the specified conversations. The conversation must be a GlodaConversation instance. You find these by first finding a message and then accessing its "conversation" attribute.
  • query.tags(tag1, tag2, tag3, ...): Add the constraint that the message must have one of the provided nsIMsgTag tags applied. (Use nsIMsgTagService to access message tags.)
  • query.starred(true/false): Add the constraint that the message must be (or not be) starred (flagged).
  • query.read(true/false): Add the constraint that the message must be (or not be) marked as read.
  • query.bodyMatches(searchString): Perform a full-text search against plaintext message bodies.
  • query.attachmentTypes(mimeType1, mimeType2, ...): Constrain to messages with attachments among the given mime types. In theory, providing no arguments should result in finding messages with any attachment, but this is somewhat untested.
  • More constraints can be found in the three js files given further below. From https://developer.mozilla.org/docs/Mozilla/Thunderbird/Thunderbird_extensions/Demo_Addon, Demo3, it seems that the attributeName given in these files is the constraintname to be used (e.g. query.subjectMatches(searchString) for message subject (compare fundattr.js line 145 ).

Create a collection from the query

Your listener is notified as messages are added to the collection as the database query completes. You may also see new messages show up if new messages are indexed that meet the constraints.

let myListener = {
  /* called when new items are returned by the database query or freshly indexed */
  onItemsAdded: function myListener_onItemsAdded(aItems, aCollection) {
  },
  /* called when items that are already in our collection get re-indexed */
  onItemsModified: function myListener_onItemsModified(aItems, aCollection) {
  },
  /* called when items that are in our collection are purged from the system */
  onItemsRemoved: function myListener_onItemsRemoved(aItems, aCollection) {
  },
  /* called when our database query completes */
  onQueryCompleted: function myListener_onQueryCompleted(aCollection) {
  }
};
let collection = query.getCollection(myListener);

Message attributes

Look at the pretty messages!

The max number of messages which are returned is governed by a preference:

"mailnews.database.global.search.msg.limit"

Although you can deal with the messages as they show up via the listener, the list of messages in the collection is available in collection.items. Each message is a GlodaMessage, whose database-row attributes are implemented/defined in gloda's datamodel.js. However, many attributes are dynamically contributed by built-in logic (fundattr.js and explattr.js) as well as other extensions.

The database-row attributes are:

  • id: The gloda message id. This is a locally unique identifier.
  • folder: The folder the message is found in, as represented by a GlodaFolder instance.
  • conversation: The conversation the message belongs to, as represented by a GlodaConversation instance.

Somewhat magic attributes:

  • headerMessageID: The contents of the Message-ID header of the message. You probably should not be using this.
  • folderMessage: Return the nsIMsgDBHdr that corresponds to the message. An nsIMsgDBHdr is the low-level, old-school, Thunderbird XPCOM representation of a message. You should not need to use this unless you are dealing with other old-school code or you need to manipulate the state of a message. In the future, the STEEL layer should provide wrappers to make manipulation clean and fun. Note that this message may return "null" if gloda is unable to locate the underlying message anymore.

Attributes provided by fundattr.js:

  • from: A single GlodaIdentity corresponding to the author of the message.
  • to: A list of GlodaIdentity instances corresponding to the email addresses found on the To line of the message.
  • cc: ditto, but cc.
  • involves: A list of all GlodaIdentity instances associated with this message. Effectively, this is the contents of from/to/cc in a single list and with duplicates removed.
  • attachmentTypes: A list of the attachment mime types found on this message.

Attributes provided by explattr.js:

  • tags: A list of the nsIMsgTags applied to this message.
  • starred: A boolean indicating whether this message is starred/flagged or not.
  • read: A boolean indicating whether this message is read or not.

Want a GlodaMessage when you already have an nsIMsgDBHdr?

Gloda.getMessageCollectionForHeader(aMsrHdr, aListener, aData) returns a collection (with your provided listener and data). Keep in mind that gloda is not infallible and it's conceivable that your collection may end up with no messages in it.

Have a GlodaMessage and want the rest of the messages in the conversation?

glodaMessage.conversation.getMessagesCollection(aListener, aData) returns a collection that should contain all of the messages gloda knows about that belong to the conversation. Keep in mind that duplicate messages can and will appear. (A duplicate message is a message with the same Message-Id header.)