Extending the compose UI with compose actions

  • Google Workspace add-ons can automate composing emails in Gmail by providing a UI when creating new messages or replies.

  • Add-ons use a compose trigger function defined in the manifest to build this UI, which is displayed when composing a draft.

  • Building a compose add-on involves adding a manifest field, implementing a compose trigger function, and creating callback functions for UI interactions.

  • The compose UI uses the Apps Script Card service to construct cards and widgets, similar to the message UI.

  • Add-ons can insert content into drafts using the Card service's extended classes for updating draft subject, body, and recipients.

In addition to providing a card-based interface when a user is reading a Gmailmessage, Google Workspace add-ons that extend Gmailcan provide another interface when the user is composing new messages orreplying to existing ones. This allows Google Workspace add-ons to automate the task of composing emails for the user.

Accessing the add-on compose UI

There are two ways to view an add-on's compose UI. The first way is to startcomposing a new draft or reply while the add-on is already open. The secondway is to start the add-on while composing a draft.

Either case causes the add-on to execute the correspondingcompose trigger function, defined in the add-onmanifest.The compose trigger function builds the compose UI for that composeaction, which Gmail then displays to the user.

Building a compose add-on

You can add compose functionality to an add-on by following these general steps:

  1. Add thegmail.composeTriggerfield to the add-on script projectmanifestand update the manifestscopes to includethose required for compose actions.
  2. Implement a compose trigger function that builds a compose UI when thetrigger fires. Compose trigger functions return either a singleCard object or an array ofCard objects that comprisethe compose UI for the compose action.
  3. Implement associated callback functions needed to react to the user'scompose UI interactions. These functions are not the compose action itself(which only causes the compose UI to appear); rather, these are theindividual functions that govern what happens when different elements of thecompose UI are selected. For example, a UI card containing a buttonusually has an associated callback function that executes when a user clicksthat button. The callback function for widgets that update the draft messagecontent should return aUpdateDraftActionResponseobject.

Compose trigger function

An add-on's compose UI is built the same way as the add-on's messageUI—using the Apps ScriptCard service to constructcards and fill them withwidgets.

You must implement thegmail.composeTrigger.selectActions[].runFunctionthat you define in your manifest. The compose trigger function must returneither a singleCard object oran array ofCard objectsthat comprise the compose UI for that action. These functions are very similartocontextual trigger functionsand should build cards in the same way.

Warning: For security reasons, add-onscan't silently change Google Workspace or third-partyfile access permissions. For example, an add-on can't silentlyadd email recipients to the set of accounts that can view a Dropbox file.Instead, the add-on must inform users that the permission change is occurring.add-ons that don't inform users of such changes can't passadd-on review.

Compose trigger event objects

When a compose action is selected, it executes the corresponding compose triggerfunction and passes the function anevent objectas a parameter. The event object can carry information about the add-on contextand the draft being composed to the trigger function.

SeeEvent object structurefor details on how information is arranged in the event object. The informationcontained in the event object is partially controlled by the value of thegmail.composeTrigger.draftAccessmanifest field:

Note: UsingMETADATA draft access requires that the add-on manifest includethehttps://www.googleapis.com/auth/gmail.addons.current.message.metadataGmail scope.

Inserting content into active drafts

Typically a Google Workspace add-on compose UI providesthe user options and control that help compose a message. For these use cases,once the user has made selections in the UI the add-on interprets the selectionsand updates the current working email draft accordingly.

To make it easier to update the current draft email, theCard servicehas been extended with the following classes:

Typically an add-on compose UI includes a 'Save' or 'Insert' widget that a usercan click to indicate they are done making selections in the UI and want theirchoices to be added to the email they are composing. To add thisinteractivity, the widget should havean associatedAction object thatinstructs the add-on to run a specific callback function when the widget isclicked. You must implement these callback functions. Each callback function shouldreturn a builtUpdateDraftActionResponseobject that details the changes to make to the current draft email.

Example 1

The following code snippet shows how to build a compose UI that updates the subject, and To, Cc, Bcc recipients of the current email draft.

/***ComposetriggerfunctionthatfireswhenthecomposeUIis*requested.BuildsandreturnsacomposeUIforinsertingimages.**@param{event}eThecomposetriggereventobject.Notusedin*thisexample.*@return{Card[]}*/functiongetComposeUI(e){return[buildComposeCard()];}/***Buildacardtodisplayinteractivebuttonstoallowtheuserto*updatethesubject,andTo,Cc,Bccrecipients.**@return{Card}*/functionbuildComposeCard(){varcard=CardService.newCardBuilder();varcardSection=CardService.newCardSection().setHeader('Update email');cardSection.addWidget(CardService.newTextButton().setText('Update subject').setOnClickAction(CardService.newAction().setFunctionName('applyUpdateSubjectAction')));cardSection.addWidget(CardService.newTextButton().setText('Update To recipients').setOnClickAction(CardService.newAction().setFunctionName('updateToRecipients')));cardSection.addWidget(CardService.newTextButton().setText('Update Cc recipients').setOnClickAction(CardService.newAction().setFunctionName('updateCcRecipients')));cardSection.addWidget(CardService.newTextButton().setText('Update Bcc recipients').setOnClickAction(CardService.newAction().setFunctionName('updateBccRecipients')));returncard.addSection(cardSection).build();}/***Updatesthesubjectfieldofthecurrentemailwhentheuserclicks*on"Update subject"inthecomposeUI.**Note:ThisisnotthecomposeactionthatbuildsacomposeUI,but*ratheranactiontakenwhentheuserinteractswiththecomposeUI.**@return{UpdateDraftActionResponse}*/functionapplyUpdateSubjectAction(){//Getthenewsubjectfieldoftheemail.//Thisfunctionisnotshowninthisexample.varsubject=getSubject();varresponse=CardService.newUpdateDraftActionResponseBuilder().setUpdateDraftSubjectAction(CardService.newUpdateDraftSubjectAction().addUpdateSubject(subject)).build();returnresponse;}/***UpdatestheTorecipientsofthecurrentemailwhentheuserclicks*on"Update To recipients"inthecomposeUI.**Note:ThisisnotthecomposeactionthatbuildsacomposeUI,but*ratheranactiontakenwhentheuserinteractswiththecomposeUI.**@return{UpdateDraftActionResponse}*/functionapplyUpdateToRecipientsAction(){//GetthenewTorecipientsoftheemail.//Thisfunctionisnotshowninthisexample.vartoRecipients=getToRecipients();varresponse=CardService.newUpdateDraftActionResponseBuilder().setUpdateDraftToRecipientsAction(CardService.newUpdateDraftToRecipientsAction().addUpdateToRecipients(toRecipients)).build();returnresponse;}/***UpdatestheCcrecipientsofthecurrentemailwhentheuserclicks*on"Update Cc recipients"inthecomposeUI.**Note:ThisisnotthecomposeactionthatbuildsacomposeUI,but*ratheranactiontakenwhentheuserinteractswiththecomposeUI.**@return{UpdateDraftActionResponse}*/functionapplyUpdateCcRecipientsAction(){//GetthenewCcrecipientsoftheemail.//Thisfunctionisnotshowninthisexample.varccRecipients=getCcRecipients();varresponse=CardService.newUpdateDraftActionResponseBuilder().setUpdateDraftCcRecipientsAction(CardService.newUpdateDraftCcRecipientsAction().addUpdateToRecipients(ccRecipients)).build();returnresponse;}/***UpdatestheBccrecipientsofthecurrentemailwhentheuserclicks*on"Update Bcc recipients"inthecomposeUI.**Note:ThisisnotthecomposeactionthatbuildsacomposeUI,but*ratheranactiontakenwhentheuserinteractswiththecomposeUI.**@return{UpdateDraftActionResponse}*/functionapplyUpdateBccRecipientsAction(){//GetthenewBccrecipientsoftheemail.//Thisfunctionisnotshowninthisexample.varbccRecipients=getBccRecipients();varresponse=CardService.newUpdateDraftActionResponseBuilder().setUpdateDraftBccRecipientsAction(CardService.newUpdateDraftBccRecipientsAction().addUpdateToRecipients(bccRecipients)).build();returnresponse;}

Example 2

The following code snippet shows how to build a compose UI that inserts imagesinto the current draft email.

/**     * Compose trigger function that fires when the compose UI is     * requested. Builds and returns a compose UI for inserting images.     *     * @param {event} e The compose trigger event object. Not used in     *         this example.     * @return {Card[]}     */functiongetInsertImageComposeUI(e){return[buildImageComposeCard()];}/**     * Build a card to display images from a third-party source.     *     * @return {Card}     */functionbuildImageComposeCard(){//GetashortlistofimageURLstodisplayintheUI.//Thisfunctionisnotshowninthisexample.varimageUrls=getImageUrls();varcard=CardService.newCardBuilder();varcardSection=CardService.newCardSection().setHeader('My Images');for(vari=0;i <imageUrls.length;i++){varimageUrl=imageUrls[i];cardSection.addWidget(CardService.newImage().setImageUrl(imageUrl).setOnClickAction(CardService.newAction().setFunctionName('applyInsertImageAction').setParameters({'url':imageUrl})));}returncard.addSection(cardSection).build();}/**     * Adds an image to the current draft email when the image is clicked     * in the compose UI. The image is inserted at the current cursor     * location. If any content of the email draft is currently selected,     * it is deleted and replaced with the image.     *     * Note: This is not the compose action that builds a compose UI, but     * rather an action taken when the user interacts with the compose UI.     *     * @param {event} e The incoming event object.     * @return {UpdateDraftActionResponse}     */functionapplyInsertImageAction(e){varimageUrl=e.parameters.url;varimageHtmlContent='<img style=\"display: block\" src=\"'+imageUrl+'\"/>';varresponse=CardService.newUpdateDraftActionResponseBuilder().setUpdateDraftBodyAction(CardService.newUpdateDraftBodyAction().addUpdateContent(imageHtmlContent,CardService.ContentType.MUTABLE_HTML).setUpdateType(CardService.UpdateDraftBodyType.IN_PLACE_INSERT)).build();returnresponse;}

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-12-11 UTC.