Inbox SDK
Getting Started What is this? Quick Start
Structuring Your App
Required Setup Loading Your App Loading Dependencies
Concepts
How It Works Views & Events Compatibility
API Reference InboxSDK.*
Compose
ComposeView ComposeButtonDescriptor StatusBarDescriptor StatusBarView
Lists
ThreadRowView ThreadRowButtonDescriptor ThreadRowActionButtonDescriptor LabelDescriptor ImageDescriptor ThreadRowDateDescriptor ThreadRowAttachmentIconDescriptor ThreadRowDraftLabelDescriptor Enums and Constants
Conversations
ThreadView MessageView ContentPanelView AttachmentCardView AttachmentCardClickEvent
ConversationsDescriptors
AttachmentCardOptions AttachmentCardNoPreviewOptions ContentPanelDescriptor DownloadButtonDescriptor CustomButtonDescriptor AttachmentsToolbarButtonDescriptor MessageViewLinkDescriptor MessageAttachmentIconDescriptor
Enums and Constants
Toolbars
ToolbarButtonDescriptor AppToolbarButtonDescriptor AppToolbarButtonView Enums and Constants
Router
RouteView CustomRouteView ListRouteView SectionView CollapsibleSectionView CustomListDescriptor ThreadDescriptor SectionDescriptor RowDescriptor Enums and Constants
NavMenu
NavItemView NavItemDescriptor NavItemTypes CreateAccessoryDescriptor IconButtonAccessoryDescriptor DropdownButtonAccessoryDescriptor
Widgets
ModalOptions ModalButtonDescriptor MoleOptions MoleButtonDescriptor ModalView DrawerOptions MoleView DrawerView
ButterBar
MessageDescriptor SavingMessageDescriptor
Search
AutocompleteSearchResult SearchQueryRewriter
User
Keyboard Shortcuts
KeyboardShortcutHandle KeyboardShortcutDescriptor
UI
ButtonView TextInputView CheckboxView
Common Data Types
Contact DropdownView PositionOptions
Resources Example Apps Inbox Support Preview
Advanced Patterns
Promises Streams
FAQ Changelog Support
Getting Started

What is this?

The InboxSDK is a library for building browser extensions for Gmail and soon Inbox too. It provides APIs for browser extensions to interact with and extend the Gmail and Inbox UI. The SDK is built so that multiple extensions can use it on a page at once without conflicting with each other.

Note: Don't forget to register for an AppId to run your app in production, it's quick and free: AppId Registration

The library is intended to facilitate the creation of extensions like our Streak extension. The library is sophisticated enough for the Streak extension itself to be built on, but the library does not provide facilities for other extensions to interact with user data specific to the Streak extension (pipelines, boxes, etc.). To integrate with Streak itself, see the Streak API docs.

InboxSDK's support for Gmail is mature and proven in extensions used by millions of users. We're still developing our support for Google Inbox, and developers can opt in early to try out the InboxSDK in Inbox.

Quick Start

Download the SDK here:

Download inboxsdk.js Download Hello World Sample App

Hello World! Chrome Extension

Here's how simple it is to build a basic app, you need two files: myapp.js which is your application code that interacts with the SDK, and the manifest.json which describes a basic Chrome extension.

InboxSDK.load(1, 'YOUR_APP_ID_HERE').then(function(sdk){ // the SDK has been loaded, now do something with it! sdk.Compose.registerComposeViewHandler(function(composeView){ // a compose view has come into existence, do something with it! composeView.addButton({ title: "My Nifty Button!", iconUrl: 'https://example.com/foo.png', onClick: function(event) { event.composeView.insertTextIntoBodyAtCursor('Hello World!'); }, }); }); }); { "manifest_version": 2, "name": "Hello World Extension", "version": "1.0", "permissions": [ "https://mail.google.com/", "https://inbox.google.com/" ], "content_scripts" : [ { "matches": ["https://mail.google.com/*", "https://inbox.google.com/*"], "js": ["inboxsdk.js", "myapp.js"] } ] }

Running your Hello World! Extension

To test your new app, open Chrome to chrome://extensions and check the "Developer Mode" checkbox. Then click on "Load Unpacked Extension" and point it to your extension directory. Next, open Gmail and stand in awe. For more details on testing Chrome extensions, see Chrome Getting Started Docs.

Structuring Your App

Required Setup

Browser extensions built using the InboxSDK are structured like normal browser extensions. You must additionally:

  1. inboxsdk.js should be placed inside your extension directory
  2. The manifest.json (Chrome) or info.plist (Safari) needs to list the above file as a content script which runs on "https://mail.google.com" and "https://inbox.google.com"
  3. You must register for an AppId to use your app in production. This is a 100% free step and takes about 5 seconds to complete. Your AppId will be tied to your Google account.
  4. One of the "Loading Your App" methods must be done as described below

For more basics of Chrome extensions, see: Chrome Extension Reference

For more basics of Safari extensions, see: Safari Extension Reference

Loading Your App

1. Local App (Basic)

The simplest and easiest way to use the SDK is to have a myapp.js file placed inside your extension. This file will then load the SDK using .

InboxSDK.load(1, 'YOUR_APP_ID_HERE').then(function(sdk){ // your app code using 'sdk' goes in here }); { "manifest_version": 2, "name": "Hello World Extension", "version": "1.0", "permissions": [ "https://mail.google.com/", "https://inbox.google.com/" ], "content_scripts" : [ { "matches": ["https://mail.google.com/*", "https://inbox.google.com/*"], "js": ["inboxsdk.js", "myapp.js"] } ] }

2. Remote App

The previous method, while simple, implies that you must release a new extension (typically to the Chrome Web Store) if you want to make changes to the app. For high usage or frequently updated apps, you may not want to wait for the chrome extension system to update all your users extensions to the latest version.

To handle this scenario, you can host your actual application code on your own server (or somewhere convenient) and remotely load it when needed. This allows you to make updates to it and your users will simply need to refresh Gmail to get the changes.

The InboxSDK has convenient functions for remotely loading your application code, you'll need the following files.

// This file will get downloaded and run by your extension making it easy to update // Don't forget to add this domain to your manifest.json! InboxSDK.loadScript('https://www.myserver.com/myapp.js') // notice how this file is exactly the same as what content.js would have been in Method 1 above? InboxSDK.load(1, 'YOUR_APP_ID_HERE').then(function(sdk){ // your app code using 'sdk' goes in here }); { "manifest_version": 2, "name": "Hello World Extension", "version": "1.0", "permissions": [ "https://mail.google.com/", "https://inbox.google.com/", "https://www.myserver.com/" ], "content_scripts" : [ { "matches": ["https://mail.google.com/*", "https://inbox.google.com/*"], "js": ["inboxsdk.js", "loader.js"] } ] }

Loading Dependencies

You may want to load other JS libraries like mapping or charting libraries for your application to use. You can compile these libraries directly into your myapp.js (for libraries like jquery, this may make sense), but sometimes you may want to remotely load these instead.

We recommend that you load these dependencies in your myapp.js file so that they can be updated in the same way your application can.

The function provides a convenient way to remote load these scripts. This function returns a promise which can be used to chain dependencies or load them in parallel. Conveniently, also returns a promise so you can fine tune your ordering of dependencies and the SDK. The following example shows how you would parallel load a dependency.

// This file will get downloaded and run by your extension making it easy to update // Don't forget to add this domain to your manifest.json! InboxSDK.loadScript('https://www.myserver.com/myapp.js') Promise.all([ InboxSDK.load(1, 'YOUR_APP_ID_HERE'), InboxSDK.loadScript('https://www.somedependency.com/somedependency.js') ]) .then(function(results){ var sdk = results[0]; // the rest of your app code here }); { "manifest_version": 2, "name": "Hello World Extension", "version": "1.0", "permissions": [ "https://mail.google.com/", "https://www.myserver.com" ], "content_scripts" : [ { "matches": ["https://mail.google.com/*"], "js": ["inboxsdk.js", "loader.js"] } ] }

Concepts

How It Works

To use the InboxSDK, you must include the inboxsdk.js file in your extension. This file is just a small shim and is only responsible for remotely loading the full implementation of the SDK. This is done so that the actual implementation of the SDK can be updated to keep compatibility with Gmail without requiring you to update your extension for every change. The implementation is often updated to maintain compatibility with Gmail, fix bugs, and add new SDK features. All that is required for your end users to reap this benefit is for them to refresh Gmail in their browser.

Since the SDK is remotely loaded, you can't start interacting with it until its been loaded.

The inboxsdk.js shim defines a few functions which you can directly use immediately without waiting for the remote implementation to load. These are documented in the InboxSDK.* namespace.

Views & Events

Several methods in the InboxSDK return View types. These View classes have a variety of functionality depending on the UI element they represent. However, one critical commonlaity is that they are all EventEmitters. This means that you can subscribe to a variety of events that each View emits.

The events they emit are all documented in their respective documentation sections (i.e. see has a section for events). One commonality is that they all emit a destroy event and have their destroyed property set to true when they are no longer available in the page. It's often useful to subscribe to this event and then cleanup any resources/memory/references you may no longer need. Performance inside Gmail/Inbox is important to maintain, so it's critical you release any relevant resources when this event is emitted.

To subscribe to events, refer to the documentation for EventEmitters. Here's a simple example showing how to subscribe to events:

InboxSDK.load(1, 'YOUR_APP_ID_HERE').then(function(sdk){ sdk.Compose.registerComposeViewHandler(function(composeView){ composeView.on('recipientsChanged', function(event) { console.log('Recipients have changed to: ' + event); }); composeView.on('destroy', function(event) { console.log('compose view going away, time to clean up'); }); }); });

Compatibility

The SDK is currently at version 1 and when loading the SDK that is the number you should specify. The SDK may add backwards compatible API's to the current version, but incompatible changes will come with a version update. Your code is guranteed to work so long as you specify the correct version number AND that version number is at most two releases old.

API Reference

InboxSDK.*

LoadOptions

LoadScriptOptions

Compose

InboxSDK.load(1, 'YOUR_APP_ID_HERE').then(function(sdk){ sdk.Compose.registerComposeViewHandler(function(composeView){ console.log("compose view exists!"); }); });

ComposeView


Example

InboxSDK.load(1, 'YOUR_APP_ID_HERE').then(function(sdk){ sdk.Compose.registerComposeViewHandler(function(composeView){ composeView.addButton({ title: "My Nifty Button!", iconUrl: 'https://example.com/foo.png', onClick: function(event) { event.composeView.insertBodyTextAtCursor('Hello World!'); }, hasDropdown: false, type: "MODIFIER", orderHint: 0 }); }); });

ComposeButtonDescriptor

StatusBarDescriptor

StatusBarView

Lists

ThreadRowView

ThreadRowButtonDescriptor

ThreadRowActionButtonDescriptor

LabelDescriptor

ImageDescriptor

ThreadRowDateDescriptor

ThreadRowAttachmentIconDescriptor

ThreadRowDraftLabelDescriptor

Enums and Constants

Conversations

ThreadView

MessageView

ContentPanelView

AttachmentCardView

AttachmentCardClickEvent

ConversationsDescriptors

AttachmentCardOptions

AttachmentCardNoPreviewOptions

ContentPanelDescriptor

DownloadButtonDescriptor

CustomButtonDescriptor

AttachmentsToolbarButtonDescriptor

MessageViewLinkDescriptor

MessageAttachmentIconDescriptor

MessageViewToolbarButtonDescriptor

Enums and Constants

Toolbars

ToolbarButtonDescriptor

AppToolbarButtonDescriptor

AppToolbarButtonView

Enums and Constants

Router

RouteView

Enums and Constants

NavMenu

CreateAccessoryDescriptor

IconButtonAccessoryDescriptor

Widgets

ModalOptions

ModalButtonDescriptor

MoleOptions

MoleButtonDescriptor

DrawerOptions

ModalView

MoleView

DrawerView

ButterBar

MessageDescriptor

SavingMessageDescriptor

Search

AutocompleteSearchResult

SearchQueryRewriter

User

Keyboard Shortcuts

KeyboardShortcutHandle

KeyboardShortcutDescriptor

Common Data Types

Contact

PositionOptions

Resources

Example Apps

We've developed several sample extensions that demostrate the use of the InboxSDK. The examples are all hosted on GitHub. If you'd like to help develop more samples, let us know!

Inbox Support Preview

We've been hard at work at getting the InboxSDK to work in Google's Inbox too, and we're finally ready to make our initial support public!

To opt in now, pass 2 as the API version parameter to InboxSDK.load. This will enable the InboxSDK on Google Inbox. This will also disable all previously-deprecated functionality, so if you were getting warnings in the console before from the InboxSDK, then those will be upgraded to errors.

Many APIs have support now, but not all of them. We've annotated our API documentation with Gmail and Inbox icons to show the current status of support. Please let us know if you run into any issues while using the SDK in Inbox, or have functionality in mind that you want to see ported over soon!

Advanced Patterns

Promises

Several of our API methods accept or provide a promise for a certain value instead of the value itself. A promise is an object that represents an eventual value, and allows callbacks to be registered to be called when the value becomes present. Promises are standardized and are natively available as part of Javascript in modern browsers. Promises help to provide a consistent interface to writing asynchronous code.

Here is a simple example of creating a promise that resolves to a value after a second, and then an example of how to listen to the promise:

var promise = new Promise(function(resolve, reject) { setTimeout(function() { resolve('foo'); }, 1000); }); promise.then(function(value) { console.log("received", value); }); // Prints "received foo" after one second.

Promises can also be created by chaining from existing promises. For more information on promises, see resources such as the HTML5 Rocks or Mozilla Developer Network pages on promises.

Streams

Several of our API methods accept reactive streams as arguments. A reactive stream is an object that represents a series of eventual values, like a promise that can resolve repeatedly with new values over time. Streams are implemented in libraries such as Kefir, Bacon.js, and Reactive Extensions for Javascript, which are each supported by the InboxSDK. Streams help to provide a consistent and composable interface to writing asynchronous code, like promises.

In order to create streams, you must include one of the above libraries in your extension. Here is an example of creating and then consuming a stream using the Kefir library:

var stream = Kefir.stream(function(emitter) { var timer = setInterval(function() { emitter.emit('foo'); }, 1000); // Return a function to be called when the stream is unsubscribed from. // Unlike promises, streams can know when they're no longer listened to! return function() { clearInterval(timer); }; }); stream.take(5).onValue(function(value) { console.log("received", value); }); // Prints "received foo" five times each one second apart, and then stops.

Note that reactive libraries often contain many specialized functions for creating streams from timers, event listeners, and other streams. This example purposefully uses a general method instead that can be quickly adapted to many uses. The above example should be enough to show you how to interact with the InboxSDK's stream-compatible methods, but if you want more information on reactive streams in order to use them more effectively, some recommended resources include the documentation of the above libraries, Netflix's talk on Reactive Programming, and The introduction to Reactive Programming you've been missing.

FAQ

What browsers are supported?

Chrome and Safari are currently supported. Chrome version 36 and Safari 7 are the minimum versions we support.

Firefox support is under consideration; please let us know if you're interested.

Changelog

The InboxSDK loads its code remotely from our servers, so users get the latest code and bug fixes automatically without extension developers being required to make any changes. We also often introduce new features over time, and on occasion we deprecate old APIs and recommend new ones. These API changes will be listed here and announced in emails to registered developers as necessary.

2017-07-26 Lists.registerThreadRowViewHandler, ThreadRowView.addLabel, ThreadRowView.addImage, ThreadRowView.replaceDraftLabel, ThreadRowView.getSubject, ThreadRowView.getThreadIDAsync, ThreadRowView.getThreadIDIfStableAsync, ThreadRowView.getDraftID, ThreadRowView.getVisibleDraftCount, ThreadRowView.getVisibleMessageCount, and ThreadRowView.getContacts are now all supported in Inbox.

2017-07-26 Toolbars.registerThreadButton, Toolbars.registerToolbarButtonForList, and Toolbars.registerToolbarButtonForThreadView are now supported in Inbox.

2017-07-26 The new function Toolbars.registerThreadButton has been added which supersedes Toolbars.registerToolbarButtonForList and Toolbars.registerToolbarButtonForThreadView.

2017-06-22 The ComposeView "sent" event is now properly supported in Inbox. Its threadID and messageID properties have been deprecated in favor of its new asynchronous getThreadID() and getMessageID() methods.

2017-06-14 Deprecated the getThreadID, getThreadIDIfStable, and getMessageID methods of ThreadView, ThreadRowView, and MessageView in favor of getThreadIDAsync, getThreadIDIfStableAsync, and getMessageIDAsync methods. This is done because it turns out that in some cases in Inbox the InboxSDK needs to make network requests against Gmail in order to correctly resolve the ID.

2017-06-14 Fixed the modal and its backdrop to display over any open DrawerView.

2017-05-16 Fixed an issue where MessageView.getBodyElement() would on a message if it was an exact duplicate of a previous message within the same thread. (Surprisingly, Gmail put a different classname on the element in that specific case.)

2017-04-13 The InboxSDK was updated to deal with changes to the format of some of Gmail's network requests. The custom thread list feature was briefly broken today after Gmail's change and before our update.

2017-04-11 Inbox support for ComposeView's getDraftID() method and some of its events was added.

2017-01-23 Our initial Inbox support is live!

2017-01-09 The new ThreadView sidebar design has replaced the old design after an opt-in period.

2016-11-14 The ThreadView sidebar has been re-designed, and developers are encouraged to opt-in, try out the new design, and give feedback before it becomes the default.

2016-09-14 Added the DrawerView.associateComposeView method.

2016-08-18 Added the AttachmentCardClickEvent.getDownloadURL() method, and deprecated the AttachmentCardView.getDownloadURL() method. In Inbox, the download URL of an attachment card view can't be retrieved until after the card's preview overlay has been opened by the user, so the API has been restructured to reflect this.

2016-08-09 Added the Conversations.registerFileAttachmentCardViewHandler() method to allow AttachmentCardViews to be handled directly rather than require them to be retrieved from a MessageView instance. Google Inbox often shows attachment cards outside of messages, so this API is being introduced to allow code to be made forward-compatible with that case now.

2016-07-21 Added the Widgets.showDrawerView method and the DrawerView class.

2015-12-14 Added the ComposeView.getCurrentDraftID() method to allow determining whether a ComposeView has been assigned a draft ID yet.

2015-12-10 Added the ThreadRowView.getDraftID() method to allow identifying the draft ID from a thread row that represents a draft.

2015-12-09 Added the ComposeView.getDraftID() method.

2015-06-17 Added the ComposeView.getInitialMessageID() method and the "messageID" property on the ComposeView destroy event object. The ComposeView.getMessageID() method and the ComposeView messageIDChange event have been deprecated as they weren't dependable for use directly because there was no guarantee that the message ID hadn't been changed on the server by the time a user tried to do anything with the message ID.

2015-06-26 Deprecate User.getUserContact() in favor of User.getEmailAddress() because it seems that there are situations that the page doesn't contain the data we need to meet the API of User.getUserContact(), and its usage is rare.

2015-06-17 Added the Widgets.showMoleView() method.

Support

Questions? Bugs? Feature Requests? Our team is active on our InboxSDK mailing list, ask away!