Gmail APIs

This document describes what Gmail contextual gadgets are, how to write them, how to install them, and how to diagnose and fix some common issues. Gmail contextual gadgets can be listed for sale in the Google Apps Marketplace or used within in-house applications installed through the Google Apps console.



Prerequisites

This document assumes:

What is a Gmail contextual gadget?

A Gmail contextual gadget is a gadget that is triggered by clues in Gmail, such as the contents of Subject lines and email messages. For example, Gmail already provides a YouTube contextual gadget. If the body of an email contains a link to a YouTube video, a clickable thumbnail view of the video appears at the bottom of the email.

There are two development and deployment models:

  • Develop a Gmail contextual gadget for use within a single organization's Google Apps domains (an in-house application).
  • List the gadget for sale on the Google Apps Marketplace.

A Gmail contextual gadget can be triggered by content in any of the following parts of an email:

  • From
  • To
  • CC
  • Subject
  • Body
  • Sent/received timestamps

The implementation of a Gmail contextual gadget consists of two parts: the gadget spec and one or more extractors.

Extractor
Detects contextual clues in email, determines which types of content will trigger the gadget, and passes the triggering content to the gadget. An extractor does this by comparing a given regular expression to content in one or more given parts of each individual email message (From:, To:, etc.). In the YouTube gadget, the extractor checks the subject line and body of the email for strings that match the pattern of a YouTube URL (anything like http://www.youtube.com/watch?v=LQ-jv8g1YVI. Google has provided a set of extractors which you can fine-tune by specifying regular expressions as filters; see Using pre-canned extractors. You may also choose to write your own custom extractors for more finely-grained matching.
Gadget spec
Takes action based on the content passed in from an extractor. The gadget spec includes client-side logic and UI. In the YouTube gadget, the gadget spec accepts the YouTube URL and draws a thumbnail view of the video at the bottom of the email, which you can click to play the video--right inside Gmail.

Overview of developing a Gmail contextual gadget

This section lists the development steps and provides links for more details at each step. It also explains why using certain development frameworks can help make your gadgets safer.

Summary of steps

  1. Use JQuery, or write JavaScript that conforms to ECMAScript 5 Strict Mode.
  1. Choose one or more pre-canned extractors or write a custom extractor. This determines which type of content will trigger your gadget.
  2. Write a manifest for the gadget.
  3. Write the gadget spec. This determines what the gadget will do when it is triggered.
  4. Publish the gadget spec to a location which is accessible on the public Internet. An intranet will not work. Your hard drive will not work. (Why? Google's servers need to download the gadget. If they can't reach it, then Gmail can't display it.)
  5. Install the gadget.
  6. Test the gadget by sending yourself some email. The gadget should appear in Gmail whenever you read an email that contains the right sort of content. For more tips on testing gadgets, see Publishing Your Gadget in the gadgets API site.

Using the right frameworks for security

You need to be using one or more of the following development frameworks to provide an extra layer of protection between your gadget's potential vulnerabilities and your end users:

By using these frameworks, you are making it possible for your gadgets to be protected when (in the near future) Gmail contextual gadgets begin to require Caja, a tool for securing JavaScript-based Web content. By using the right frameworks and making your gadgets "cajolable," you will participate in an increased degree of protection against malicious attacks. Caja works to mitigate XSS attacks and protect your end users from vulnerabilities in your gadget that could be exploited by outsiders.

Enabling Caja

Caja is currently supported for use within test domains, so you can begin testing to see whether your gadgets work with Caja today. To enable Caja:

  1. Add the following line to your gadget spec: <Require feature="caja"/>
  2. Add the following line to the gadget's tag in your manifest: <Param name="caja" value="enabled"/>
  3. Comment out these lines in the production version of your gadget spec and manifest. Enable Caja only in your test domain.

Best practices for Caja

If you absolutely must use development frameworks other than the ones recommended, use the following techniques to make your gadget more Caja-friendly. If you are using one or more of the recommended development frameworks, you can ignore this section.

Stick to HTML and CSS specs
Caja tends to require more strict adherence to HTML and CSS standards than some browsers do, so avoid lazy tagging and nonstandard extensions.
Use only common DOM operations
Caja supports only part of the DOM specification, so stick to the more frequently-used operations. * One specific item that is not supported is document.write(). * Some examples of supported items are document.getElementById(), node.firstChild(), and getting and setting innerHTML.

Use the supported event handlers and timers * The value of node.onevent must be a function. * Use event.target or event.relatedTarget rather than event.fromElement, which is not supported.

Follow other best practices
Follow the other best practices described on the Google Caja wiki.

Using pre-canned extractors

An extractor is a pattern matcher that pulls content from one or more specified parts of every email message (subject line, message body, etc.). Some extractors simply return whatever content is found, and others use a hard-coded regular expression to look for matching content. By choosing one or more extractors and applying filters to their output, you determine what kind of email content will trigger your gadget.

Google provides a predefined set of extractors. Each of the provided extractors returns a fairly broad category of output by default. SenderEmailExtractor returns the From: address of every email message, SubjectExtractor returns the whole subject line of every message, and so on. You can customize the input to your gadget by applying your own filters, enabling your gadget to be triggered by more specific contextual clues. See Filtering extractor output.

Limitations

  • An extractor can return a maximum of 1,000 characters in each of its output fields.
  • Extractors can not read email attachments.

Supported extractors

The following table shows the supported extractors and describes their default (pre-filtering) behavior.

Make a note of the ID and scope for each extractor you want to use. You will need this information when you write the manifest and the gadget spec.

ID google.com:EmailAddressExtractor
Description Matches email addresses in the subject and body of the message
Scope tag:google.com,2010:auth/contextual/extractor/BODY
tag:google.com,2010:auth/contextual/extractor/SUBJECT
Output Fields @email - Any email addresses found
ID google.com:EmailBodyExtractor
Description Gets the first 1,000 characters of the body of the message
Scope tag:google.com,2010:auth/contextual/extractor/BODY
Output Fields @email_body
ID google.com:EmailTimeExtractor
Description Gets the time the email was sent and received (in milliseconds since epoch)
Scope tag:google.com,2010:auth/contextual/extractor/DATE_SENT
tag:google.com,2010:auth/contextual/extractor/DATE_RECEIVED
Output Fields @date_sent
@date_received
ID google.com:HelloWorld
Description Matches the text "Hello World" (case insensitive) in the subject and body of the message
Scope tag:google.com,2010:auth/contextual/extractor/BODY
tag:google.com,2010:auth/contextual/extractor/SUBJECT
Output Fields @hello - The matched instances of "Hello World"
ID google.com:HttpLinkExtractor
Description Matches HTTP and HTTPS links in the subject and body of the message
Scope tag:google.com,2010:auth/contextual/extractor/BODY
tag:google.com,2010:auth/contextual/extractor/SUBJECT
Output Fields @url - the link URL
@host - the host part of the URL
@path - the path of the URL
ID google.com:ListExtractor
Description Matches the list ID, unsubscribe link and unsubscribe email address of the message
Scope tag:google.com,2010:auth/contextual/extractor/LIST_ID
tag:google.com,2010:auth/contextual/extractor/LIST_UNSUBSCRIBE
Output Fields @list_id - The list ID of the message
@list_unsubscribe - The list unsubscribe link and unsubscribe email address
ID google.com:MessageIDExtractor
Description Matches the Gmail frontend message id of the message (this is a 64-bit hexadecimal value, different from the RFC 822 Message-ID)
Scope tag:google.com,2010:auth/contextual/extractor/MESSAGE_ID
Output Fields @message_id - Message ID of the message
ID google.com:RawSubjectExtractor
Description Gets the Subject: line, including all annotations added by the email client, such as Re: and Fwd:
Scope tag:google.com,2010:auth/contextual/extractor/RAW_SUBJECT
Output Fields @subject
ID google.com:RecipientCCEmailExtractor
Description Gets all email addresses in the CC: line of the email
Scope tag:google.com,2010:auth/contextual/extractor/CC_EMAIL
Output Fields @recipient_cc_email
ID google.com:RecipientEmailExtractor
Description Gets all email addresses in the To: and CC: lines of the email
Scope tag:google.com,2010:auth/contextual/extractor/TO_ADDRESS
tag:google.com,2010:auth/contextual/extractor/CC_EMAIL
Output Fields @recipient_email
ID google.com:RecipientToEmailExtractor
Description Gets all email addresses in the To: line of the email
Scope tag:google.com,2010:auth/contextual/extractor/TO_ADDRESS
Output Fields @recipient_to_email
ID google.com:SenderEmailExtractor
Description Gets the email address in the From: line of the email
Scope tag:google.com,2010:auth/contextual/extractor/FROM_ADDRESS
Output Fields @sender_email
ID google.com:SubjectExtractor
Description Gets the Subject: line, stripped of any annotations added by the email client, such as Re: and Fwd:
Scope tag:google.com,2010:auth/contextual/extractor/SUBJECT
Output Fields @subject
ID google.com:USPhoneExtractor
Description Matches dash-delimited US phone numbers of the form ((1-)800-)555-5555.
Scope tag:google.com,2010:auth/contextual/extractor/BODY
tag:google.com,2010:auth/contextual/extractor/SUBJECT
Output Fields @phone_number
ID google.com:USStockTicker
Description Matches ticker symbols for US stocks in the subject and body of the message
Scope tag:google.com,2010:auth/contextual/extractor/BODY
tag:google.com,2010:auth/contextual/extractor/SUBJECT
Output Fields @LinkText1 - Name of the stock
@LinkUrl1 - URL of the stock's Google Finance page

Filtering extractor output

The provided extractors match broad categories of content: every HTTP link, every recipient's email address, and so on. To make your gadget more useful (and decrease the load on Google's servers), specify an output filter for each extractor. The filter accepts the extractor output and applies additional criteria to it. This narrows the set of content that will trigger the gadget. Try to make your filter as specific as possible. The ideal gadget is triggered only by the most meaningful subset of the possible extractor outputs.

Here's a conceptual picture of how filters work (where AA and AB are simplified stand-ins for the actual content):

How filters work

To specify the filter, add a <Param> tag to the extractor section of the gadget manifest. In the <Param> tag, give the name of the extractor output field you want to filter on and the regular expression you want to match against the extractor's default output. If the extractor has multiple output fields, you can create a filter for each of them. Use the following syntax:

<Param name="extractedField" value="regexp"/>

For example, the SenderEmailExtractor will extract every sender's email address, and therefore trigger the gadget on every email. Suppose, instead, you want to trigger the gadget only when your manager sends you email, and your manager's email address is my_boss@my_domain.com:

<Extension id="from" type="contextExtractor">
  <Name>Email Sender</Name>
  <Url>google.com:SenderEmailExtractor</Url>
  <Param name="sender_email" value="my_boss@my_domain.com"/>
  <Triggers ref="bossIsCalling"/>
  <Scope ref="senderScope"/>
  <Container name="mail"/>
</Extension>

If you really do want your gadget to be triggered by all possible values in the extractor's default output, explicitly set the regular expression as value=".*". This makes it clear that you have cast a wide net by design.

Writing a custom extractor

If you need to trigger your gadget on a contextual clue that can not be adequately described using the predefined extractors and filters, you can write your own custom extractor.

Summary of writing an extractor

Extractors are written in XML. When you create a custom extractor, you will follow these basic steps:

  • Create a new XML file.
  • In the first XML elements, specify that this is data input for a Gmail contextual gadget.
  • Specify what pattern to look for in the email content.
  • Set up one or more output fields to hold any matching content that is found.
  • When the extractor XML is finished, upload it a project in the Google Apps console.
  • Reference the custom extractor from within your application manifest.

The rest of this section goes into detail about how to achieve these steps.

Guidelines for writing an extractor

An extractor works on one email at a time. There is no concept of working with an entire email conversation (or thread). The extractor can examine and extract content from one or more of the following parts of an email message:

Email part Input field name Scope(s)
From from_email tag:google.com,2010:auth/contextual/extractor/FROM_ADDRESS
tag:google.com,2010:auth/contextual/extractor/FROM_PERSONAL
To to_email tag:google.com,2010:auth/contextual/extractor/TO_ADDRESS
tag:google.com,2010:auth/contextual/extractor/TO_PERSONAL
CC cc_email tag:google.com,2010:auth/contextual/extractor/CC_EMAIL
tag:google.com,2010:auth/contextual/extractor/CC_PERSONAL
BCC bcc_email tag:google.com,2010:auth/contextual/extractor/BCC_EMAIL
tag:google.com,2010:auth/contextual/extractor/BCC_PERSONAL
Subject subject tag:google.com,2010:auth/contextual/extractor/SUBJECT
tag:google.com,2010:auth/contextual/extractor/RAW_SUBJECT
Body body tag:google.com,2010:auth/contextual/extractor/BODY
Sent timestamp date_sent tag:google.com,2010:auth/contextual/extractor/DATE_SENT
Received timestamp date_received tag:google.com,2010:auth/contextual/extractor/DATE_RECEIVED
Message ID id tag:google.com,2010:auth/contextual/extractor/MESSAGE_ID
Mailing list list_id tag:google.com,2010:auth/contextual/extractor/LIST_ID
Mailing list unsubscribe link and email address list_unsubscribe tag:google.com,2010:auth/contextual/extractor/LIST_UNSUBSCRIBE

You can not match against files attached to emails.

To tell the extractor what to look for, use an RE2-compatible regular expression (these are similar to Perl-compatible regular expressions, or PCREs, but without backreferences or support for generalized zero-width assertions). This expression can either describe a desired pattern or an anti-pattern. For example, you can trigger the gadget for all emails from a particular domain or all emails except those from a particular domain. The expression is specified inside a <Pattern> element. For example:

<Pattern input_fields="from_email">mytest.com</Pattern>

To express negation, add the option negative="true" to the <Pattern> element. For example:

<Pattern input_fields="from_email" negative="true">mytest.com</Pattern>

You can use a list of static strings as literal matches. For example, suppose you have a list of customer IDs and you want to trigger the gadget on any email containing one of those IDs. As another example, the predefined extractor USStockTicker contains a list of all US stock symbols. To match against a list of strings, include a <DataObject> element that defines the list of strings. Then refer to the data object in the regular expression. We have added a custom extension to the RE2 syntax, ?M=, for this purpose. For an example, see Example string repository extractor.

Syntax of an extractor

Use the following syntax to write a custom extractor:

<?xml version="1.0" encoding="UTF-8"?>
<OpenCOBData id="extractorID">
  <ExtractorSpec platform="gmail" language="languageCode">
    <!-- Set up a regexp to match content. -->
    <Search input_type="text">
      <!-- input_fields - a comma-separated list of
       email parts to look in.
       Supported values: from_email, to_email, cc_email, bcc_email,
       date_sent, date_received, subject, body, id, list_id, list_unsubscribe.
       Default: subject,body. -->
      <Pattern input_fields="emailPart,emailPart...">
        <!-- In yourRegularExpression, include one or more named
         sub-patterns in angle brackets which identify substrings that
         can be referred to in @outputSource below.
         The regular expression can also contain ?M=objectType
         to refer to a <DataObject> in the same file. -->
        <![CDATA[(yourRegularExpression)]]>
      </Pattern>
    </Search>
    <!-- Set up the output. -->
    <Response platform="gmail" format="cardgadget">
      <!-- outputSource specifies what to return.
       To return part of the string that matched the expression,
       use a sub-pattern name specified in the <Pattern>.
       To return an entire email field, use a built-in
       variable: __SUBJECT__, __BODY__, __DATE_SENT__,
       __DATE_RECEIVED, __FROM_ADDRESS__, __TO_ADDRESS__,
       __CC_EMAIL__, __BCC_EMAIL__, __MESSAGE_ID__, __LIST_ID__,
       or __LIST_UNSUBSCRIBE__. In this case, you don't need to use
       the <Pattern> tag. -->
      <Output name="outputFieldName">{@outputSource}!</Output>
    </Response>
  </ExtractorSpec>

  <!-- Optional: a list of literal strings to look for. Incorporate this
   into the regular expression above by referring to objectType. -->
  <DataObject id="dataObjectID" type="objectType">
    <QueryName value="literal"/>
    ...
  </DataObject>

  <!-- Repeat to define more string repositories. -->
  <DataObject>...</DataObject>
  ...

</OpenCOBData>

Example string repository extractor

In the following example, several lists of literal strings are used to find US stock ticker symbols in email. The lists are specified in <DataObject> tags, which also define the types by which they are referenced in the search pattern (AMEXTickerType, NYSETickerType, etc.).

<?xml version="1.0" encoding="UTF-8"?>
<OpenCOBData id="USStockTicker">
  <AuthorInfo
    description="Extracts US stock tickers from emails."
    author="Avi Flambards" />
  <ExtractorSpec id="USStockTickerExtractor" platform="gmail" language="en">
    <Search>
      <Pattern input_fields="subject,body">
        <![CDATA[(?x)
        ##### This expression finds full declarations of AMEX tickers.
        ##### They are of the form 'AMEX:AIM'
        #####
        (\b(?P<exchange>AMEX)(?::\ ?)(?P<ticker>(?M=AMEXTickerType))\b)

        #####
        ##### This expression finds full declarations of NASDAQ tickers.
        ##### They are of the form 'NASD:MSFT' and 'NASDAQ: MSFT'
        #####
        |(\b(?P<exchange>NYSE)(?::\ ?)(?P<ticker>(?M=NYSETickerType))\b)

       #####
       ##### This expression will find standalone tickers like 'MSFT' if it is
       ##### unambiguously a ticker and in all caps.
       #####
       |(\b(?P<ticker>(?M=USFilteredTickerType))(?:[\s\)\],]))
       (?-x)]]>
      </Pattern>
    </Search>
    <Response platform="gmail" format="cardgadget">
      <Output name="Title">Stock Ticker</Output>
      <Output name="LinkText1">{@ticker}</Output>
      <Output name="LinkUrl1">http://finance.google.com/finance?q={@ticker}</Output>
    </Response>

    ...
  </ExtractorSpec>

  <DataObject id="AllUSStockTickersFiltered" type="USFilteredTickerType">
    <QueryName value="AAC"/>
    <QueryName value="ABL"/>
    <QueryName value="ABP"/>
    <QueryName value="ACU"/>
    ...
    <QueryName value="ZTR"/>
  </DataObject>

  <!-- Repeat for the other types referred to in the regexp:
   AMEXTickerType, etc. -->
  ...

</OpenCOBData>

Uploading a custom extractor

These steps will install your new custom extractor in a location where it may be used by your applications. You will be using the Google Apps console to upload the custom extractor.

  1. Log into the console.
  2. Do one of the following:
  3. If you already have an application manifest, upload it. If you do not yet have a manifest, you may skip this step for now.
  4. Upload your custom extractor.
  5. Your extractor is now uploaded.

To reference your extractor later, use the following naming convention: projectId:ExtractorName. You can obtain the projectId by inspecting the URL for your project in the Google Apps console. For example https://code.google.com/googleapps/console/#project:100000000000 corresponds to a projectId of 100000000000.

Writing the manifest

A manifest is an XML file that describes the structure and content of an application. The manifest is used by Google Apps Marketplace when creating a listing and by the Google Apps console when configuring a project. It is also required when installing your gadget within your test domain.

You'll start with a manifest just like any other Google Apps Marketplace manifest, as described in Application Manifest. Save your manifest in a text file.

Then you'll add some tags that are specific to Gmail contextual gadgets. You can add these tags to an existing manifest for a larger application that you are listing in the Google Apps Marketplace, or you can list the contextual gadget as a standalone product.

The syntax of the Gmail contextual gadget manifest tags is shown below. The first tag configures the extractor, the second tag configures the gadget spec, and the third tag configures the scope of the gadget by specifying what portions of email the extractor can read. (Substitute your own information for the portions surrounded with _underscores_.)

<!--  EXTRACTOR
  Configures an extractor that will be used to get context to
  trigger the gadget.  If the gadget uses multiple extractors, include a
  separate <Extension> tag for each one.
  id - give the extractor any name you like.
  <Name> - a human-readable name for display to Google Apps administrators.
  <Url> - the extractor ID, like google.com:HelloWorld or 100000000000:CustomExtractor.
  <Param> - an extractor output field & regular expression
  to filter the extractor's default output.
  <Triggers> - the same gadget id that is defined
  in the gadget element below.
  <Scope> - a scope ID defined in a scope element below. If the extractor
  can access content in multiple email parts, include a separate <Scope>
  tag for each one -- whether your gadget uses them all or not. -->
<Extension id="_testExtractor_" type="contextExtractor">
  <Name>_displayName_</Name>
  <Url>_TestExtractorId_</Url>
  <Param name="_extractedField_" value="_regexp_"/>
  <Triggers ref="_exampleGadget_"/>
  <Scope ref="_exampleScope_"/>
  <Container name="mail"/>
</Extension>

<!--  GADGET
  Configures the gadget spec.
  id - give the gadget any name you like.
  <Name> - a human-readable name for display to Google Apps administrators.
  <Url> - the location of the gadget spec. -->

<Extension id="`exampleGadget`" type="gadget">
  <Name>_displayName_</Name>
  <Url>_http://example.com/gadgets/mygadget.xml_</Url>
  <Container name="mail"/>
  <!-- Uncomment this to enable Caja. -->
  <!-- Param name="caja" value="enabled"/> -->
</Extension>

<!--  SCOPE
  Configures which email part the extractor(s) can access.
  If the extractor can access content in multiple email parts,
  include a separate <Scope> tag for each one -- whether your
  gadget uses them all or not.
  id - give the scope any name you like.
  <Url> - a URI from the documented list of supported scopes.
  If using a predefined extractor, use the scope(s) documented
  for that extractor.
  <Reason> - text to display to Google Apps domain administrators
  so that they can decide whether to grant access. -->

<Scope id="_exampleScope_">
  <Url>_scopeURI_</Url>
  <Reason>_Explanatory text for Google Apps administrators_</Reason>
</Scope>

Supported scopes

The following table shows the values allowed in the tag in the manifest for a Gmail contextual gadget.

Scope URI Description
tag:google.com,2010:auth/contextual/extractor/SUBJECT Subject: line, stripped of any annotations added by the email client, such as Re: and Fwd:
tag:google.com,2010:auth/contextual/extractor/RAW_SUBJECT Subject: line, including all annotations added by the email client, such as Re: and Fwd:
tag:google.com,2010:auth/contextual/extractor/BODY Message body
tag:google.com,2010:auth/contextual/extractor/MESSAGE_ID Unique identifier that matches the Gmail frontend message id of the message (this is a 64-bit hexadecimal value, different from the RFC 822 Message-ID)
tag:google.com,2010:auth/contextual/extractor/TO_ADDRESS Email addresses of recipients specified in the To: line
tag:google.com,2010:auth/contextual/extractor/TO_PERSONAL Names of recipients specified in the To: line (actual user names, such as John Smith)
tag:google.com,2010:auth/contextual/extractor/FROM_ADDRESS Sender's email address
tag:google.com,2010:auth/contextual/extractor/FROM_PERSONAL Sender's name (actual user name, such as Vijay Agarwal)
tag:google.com,2010:auth/contextual/extractor/CC_EMAIL Email addresses of recipients specified in the CC: line
tag:google.com,2010:auth/contextual/extractor/CC_PERSONAL Names of recipients specified in the CC: line (actual user names, such as Melissa Waterston)
tag:google.com,2010:auth/contextual/extractor/BCC_EMAIL Email addresses of recipients specified in the BCC: line
tag:google.com,2010:auth/contextual/extractor/BCC_PERSONAL Names of recipients specified in the BCC: line (actual user names, such as Yuan Li)
tag:google.com,2010:auth/contextual/extractor/LIST_ID Mailing list
tag:google.com,2010:auth/contextual/extractor/LIST_UNSUBSCRIBE Mailing list unsubscribe link and email address
tag:google.com,2010:auth/contextual/extractor/DATE_SENT Timestamp when the email was sent
tag:google.com,2010:auth/contextual/extractor/DATE_RECEIVED Timestamp when the email was received

Hello World example manifest

The following example shows the manifest for the Hello World example gadget. (Substitute your own information for the portions surrounded with _underscores_.)

<?xml version="1.0" encoding="UTF-8" ?>
<ApplicationManifest xmlns="http://schemas.google.com/ApplicationManifest/2009">

  <!-- Support info to show in the marketplace & control panel -->
  <Support>
    <!-- URL for application setup as an optional redirect during the install -->
    <Link rel="setup" href="http://_example.com_/google/setup.php?domain=${DOMAIN_NAME}" />

    <!-- URL for application configuration, accessed from the app settings
     page in the control panel -->
    <Link rel="manage" href="http://_example.com_/google/admin.php?domain=${DOMAIN_NAME}" />

    <!-- URL explaining how customers get support. -->
    <Link rel="support" href="http://_example.com_/google/support.php" />

    <!-- URL that is displayed to admins during the deletion process,
     to specify policies such as data retention, how to claim accounts, etc. -->
    <Link rel="deletion-policy" href="http://_example.com_/google/deletion-policy.php" />
  </Support>

  <!-- Name and description pulled from message bundles -->
  <Name>HelloWorld</Name>
  <Description>A simple Hello World application for testing
  Gmail contextual gadgets</Description>

  <!-- Show this link in Google's universal navigation for all users -->
  <Extension id="navLink" type="link">
    <Name>HelloWorld</Name>
    <Url>http://_example.com_/home.php?from=google&domain=${DOMAIN_NAME}</Url>
  </Extension>

  <!-- Declare our OpenID realm so our app is white listed -->
  <Extension id="realm" type="openIdRealm">
    <Url>http://_example.com_</Url>
  </Extension>

<!-- EXTRACTOR -->

<Extension id="HelloWorldExtractor" type="contextExtractor">
  <Name>Hello World</Name>
  <Url>google.com:HelloWorld</Url>
  <!-- Uncomment this Param to apply a filter to the extractor's
  default output. The example regexp below makes the match case sensitive.
  <Param name="hello" value="H[a-z]* W[a-z]*"/> -->
  <Triggers ref="HelloWorldGadget"/>
  <Scope ref="emailSubject"/>
  <Scope ref="emailBody"/>
  <Container name="mail"/>
</Extension>

<!-- GADGET -->

<Extension id="HelloWorldGadget" type="gadget">
  <Name>Hello World Gmail contextual gadget</Name>
  <Url>_http://example.com/gadgets/hello_world_gadget.xml_</Url>
  <Container name="mail"/>
  <!-- Uncomment this to enable Caja. -->
  <!-- <Param name="caja" value="enabled"/> -->
</Extension>

<!-- SCOPE -->

<Scope id="emailSubject">
  <Url>tag:google.com,2010:auth/contextual/extractor/SUBJECT</Url>
  <Reason>This application searches the Subject: line of each email
  for the text "Hello World."</Reason>
</Scope>

<Scope id="emailBody">
  <Url>tag:google.com,2010:auth/contextual/extractor/BODY</Url>
  <Reason>This application searches the message body of each email
  for the text "Hello World."</Reason>
</Scope>

</ApplicationManifest>

Writing the gadget spec

A gadget spec is an XML file that includes the programming logic and various settings for the gadget. Gmail contextual gadgets are written using the gadgets.* API. For more information about gadget specs, see Anatomy of a Gadget.

You'll start with a gadget spec just like any other, then add some items that are specific to Gmail contextual gadgets:

  • If you plan to list the gadget in the Apps Marketplace, Single Sign-On (SSO) is required. You can either write the implementation code as part of the gadget spec or reference an external file that contains the SSO code. For information about how to write the SSO code, see Single sign-on within gadgets.
  • Include a <Require> tag to declare that your gadget depends on the google.contentmatch feature.
  • Include a commented-out <Require> tag to declare that your gadget depends on Caja. Uncomment the tag within your test domain to check that your gadget works with Caja. (See Using the right frameworks for security.)
  • Include an extractors parameter in a <Param> tag to specify one or more extractor IDs. (In Gmail contextual gadgets, the extractor ID specified in the manifest overrides the extractor ID in the gadget spec. However, this line is expected as part of a standard gadget spec, so you should still include it.)
  • In the <Content> tag, set type="html", which is the only supported type of content.
  • In the <Content> tag, set view="card" to make the gadget appear at the bottom of an email. This is the only supported type of view.
  • Call google.contentmatch.getContentMatches() to return the array of all matches that were found in the email. Each match consists of a key-value pair, where the key is a string specified in the extractor and the value is the substring from your email that triggered the match.

Reusing a gadget spec

You might want to use the same gadget spec in multiple gadget projects. For example, to try out the effect of triggering the gadget with different types of content, you might use different extractors or different filters with the same gadget spec.

To do this, you must make a copy of the gadget spec file and save it to a new location for each additional gadget project. You can not use the same gadget spec URL in more than one gadget project. If you do, Google's servers can become confused and return unpredictable results.

Hello World example code

The following example shows the spec for a gadget that prints "Hello World" whenever the string "Hello World" is found in an email.

<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs title="Hello World"
    description="Matches and echoes 'Hello World' string in emails"
    height="20"
    author="Sarah M and Walter Q"
    author_email="..."
    author_location="Mountain View, CA">

    <!-- Declare feature dependencies. -->

    <!-- This one is not specific to Gmail contextual gadgets. -->
    <Require feature="dynamic-height"/>

    <!-- The next feature, Caja, is optional, and is supported for
     use only within test domains. Uncomment the tag only for
     non-production gadgets. -->
    <!-- <Require feature="caja"/> -->

    <!-- The next feature, google.contentmatch, is required for all
     Gmail contextual gadgets.
     <Param> - specify one or more comma-separated extractor IDs in
     a param named "extractors". This line is overridden by the extractor ID
     in the manifest, but is still expected to be present. -->
    <Require feature="google.contentmatch">
      <Param name="extractors">
        google.com:HelloWorld
      </Param>
    </Require>

  </ModulePrefs>

  <!-- Define the content type and display location. The settings
   "html" and "card" are required for all Gmail contextual gadgets. -->
  <Content type="html" view="card">
    <![CDATA[
      <!-- Start with Single Sign-On -->
      <script type="text/javascript" src="https://example.com/gadgets/sso.js"></script>
      <script type="text/javascript">

        <!-- Fetch the array of content matches. -->
        matches = google.contentmatch.getContentMatches();
        var matchList = document.createElement('UL');
        var listItem;
        var extractedText;

        <!-- Iterate through the array and display output for each match. -->
        for (var match in matches) {
          for (var key in matches[match]) {
            listItem = document.createElement('LI');
            extractedText = document.createTextNode(key + ": " + matches[match][key]);
            listItem.appendChild(extractedText);
            matchList.appendChild(listItem);
          }
        }
        document.body.appendChild(matchList);
        gadgets.window.adjustHeight(100);
      </script>
    ]]>
  </Content>
</Module>

Gadget features supported in Gmail

Gmail supports many gadget features in contextual gadgets. The following table provides a quick reference to some of the more useful ones, which you might want to use in your Gmail contextual gadget spec.

Feature Library Description Syntax
setprefs Sets the value of a user preference programmatically. See Gadgets API Reference: Saving State for more information. Note: Gmail currently does not provide any UI for a user to modify the preferences. <Require feature="setprefs"/>
dynamic-height Gives a gadget the ability to resize itself. See Gadgets API Reference: Managing Gadget Height for more information. <Require feature="dynamic-height"/>
locked-domain The locked-domain library isolates your gadgets from other gadgets running on the same page. You can only use this feature with type="html" gadgets. We suggest that you add this feature requirement to your gadget if your gadget stores sensitive private user data. <Require feature="locked-domain"/>
views Set the location in a container where a gadget is displayed. See gadgets.* Developer's Guide: Creating a User Interface. Note: Gmail contextual gadgets currently support only the CARD view. CANVAS view is not supported. <Content type="html" view="card">
opensocial-0.9 Allows access to social networking functions from within gadgets. <Require feature="opensocial-0.9"/>
OAuth Authorization Allows making authenticated requests to third-party services via makeRequest(). For more information, see Writing OAuth Gadgets. <OAuth/>

Installing and testing the gadget

After you have written themanifest and published the gadget spec to a location that is accessible on the Internet, you are ready to install the gadget on your own domain for testing.

  1. Log into the console.
  2. Do one of the following:
  3. Upload your application manifest.
  4. Upload your custom extractor if you have one.
  5. Deploy your application.

If you decide to sell your gadget in the Google Apps Marketplace, see the following steps on how to create a listing. You will need to re-enter your application manifest (and keep it updated when you make changes) on this second listing.

Troubleshooting

Support forums :

Gadget never triggers.

The gadget is probably failing silently due to one of the following issues:

  • Google servers find the gadget invalid for any reason. One common example would be an error in the gadget spec.
  • Gadget URL is inaccessible to the Google servers.
Part of the email body is missing.

The email is longer than the extractor's maximum output. The extracted match must be no more than 1000 characters.

Changes to gadget don't show up immediately.

Gmail is probably using a cached version of the gadget. Changes to gadgets can take some time to be reflected because of caching. Solution: Make sure you include the flag &nogadgetcache=1 in the URL when you start Gmail to test your gadgets. This flag ensures that any changes you make to gadgets will show up in your Gmail account immediately. If you reference external resources in your gadget, such as JS or CSS files located on external servers, those resources are still subject to caching.

Gadget fails to trigger when expected.

Several possible causes:

  • Single gadget spec URL being used in multiple gadget projects. If you want to reuse gadget spec code, you must make a copy of the gadget spec file and place it at a different location. Gmail contextual gadgets assume that every gadget spec URL is used only once.
  • Extractor timeout.
  • Target content outside the 1,000 character window. For example, suppose you are using the EmailBodyExtractor with a filter that looks for telephone numbers. The gadget will trigger only if the telephone number is near the beginning of the email, because EmailBodyExtractor can only return the first 1,000 characters.
  • Semantic error in an extractor output filter. If the filter is not written correctly to return the results you intended, your gadget will not trigger as expected. For example, one possible mistake would be an incorrect field name in the filter, such as typing time_sent instead of date_sent.

Resources

Getting help

About the Apps Marketplace

About gadgets

  • Gadgets API -- Tells what a gadget is and provides access to information about how to write a gadget
  • blog post -- Announces the launch of Gmail contextual gadgets and provides an overview and video
  • Google Gadget Editor -- A tool for posting gadget code to the Internet if you do not have web hosting
  • Google Apps Marketplace -- where you can list your gadget for sale
  • Caja -- Web gadget security that will (soon) be provided by Gmail contextual gadgets
  • GWT -- One of the supported Caja-friendly development frameworks
  • OpenSocial templates -- One of the supported Caja-friendly development frameworks
  • JQuery -- One of the supported Caja-friendly development frameworks

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.