Trigger Actions Directly in Email

Info below provided as-is, you may need to tweak and adjust things to suit your situation and please take note of the security concern outlined below.

There are 2 apps needed to make this solutions (explained below):

  1. Approve from Email (primary app)
  2. Keygap for Approve from Email (required to mask the primary app’s access key)

Supporting Documentation:

Embedding Forms and Buttons: HTML input tag
HTML → JSON Forms: W3C HTML JSON form submission

Similar Solutions:
@LeventK Executing a DeepLink action from an Email Silently
@Fabian Executing a DeepLink action from an Email Silently - #26 by Fabian


Currently there is no default AppSheet solution available to generate emails where an individual can execute AppSheet actions directly from the email itself. Typically they must click on a link to open the app and then click on an action within the app. In this example, a simple app was created that allows users to submit new requests into an app and email these requests to an approver. This solution solves the problem of needing to open the app to approve or reject a request allowing users to execute the Approve or Reject action directly from the email body.

Why are there 2 apps?

There is a limitation with AppSheet in that in order to receive API calls you need to use a static app access key. Normally this is not a problem when accomplishing machine to machine calls, but in this case the access key needs to be embedded in the email’s html code. This exposes a security vulnerability and creates an opportunity for someone who receives the email to copy the app’s key and send calls to update the app through the and bypass any of the app’s security filters that may be in place.

The second AppSheet app (Keygap for Approve from Email) acts as a security gap and it is this app’s access key that is sent in the email body. This is done so you only expose an app that does only one thing… send calls for the desired email actions you are wanting to create. This creates additional security because even if a user finds the keygap access key by reading the html code of an email, they would only be able to act on requests that are in the email action queue and would need to know the primary key of the records to execute the action.


There are 2 tables in this example, requests and keygap.

The requests table is where all new requests are logged and tracked to approval or rejection. This follows a typical approval workflow setup using appsheet. This only appears in the primary app.

The keygap table is used by both apps. where all pending requests are queued for the keygap app to act on when the keygap app receives a call from an email. This also has the benefit of shrinking the size of a potential attack surface to only specific pending records in this table. Records are then deleted by the keygap app once the action is executed.

Potential Security Concerns

As highlighted above the purpose of the keygap app and separate keygap table is to shrink the attack surface to only requests that are currently pending. However this does not remove all risk. If the email itself is forwarded to other individuals they will have the ability to approve/reject the request even if they cannot approve the request in the app. If the risk is a high enough concern for an organization, one could add a pin number system to the app and capture a pin number in the email’s post form as an additional verification that the approver is the person clicking the approve or reject button.

How the App Works

  1. The main app sends a formatted email via Notify approver workflow to an email address. The email body contains html form tags that generate the approve or reject actions with the reference to the primary key of the record to be updated. This makes use of the Invoking the AppSheet API service.
  2. The main app also adds the request to the keygap table with a pending status.
  3. The approver receives an email that summarizes the request and has 2 options to approve or reject.
  4. When Approve/rejected button is clicked an post call is sent to the keygap app to update the respective record in the keygap table with the approvers intent.
  5. When the record is updated with the approvers intent in the keygap table, a workflow called Update Record is triggered that sends a post call to the Main app to trigger either Approve or Disapprove for specific record
  6. This update in the main app triggers a workflow called Approved or Rejected that sends an email to the approver to notify them that the request was successfully approved or rejected.

Thanks you Rich, for sharing awosome knowledge. I put this into our library.
Will dig in deeper, as it may take a bit of time to learn all the detail of this trick.

I have a impression that probably we can use the button element on email body for other purpose, for instance simply open up that app etc.

Wondering if we can pull the cdn with tab in emai body? to use the css liberary etc to make our life easier to decorate the email body?


Yes you are right, there are probably plenty ideas that can be created as well. I hope to see many great ideas from the community! I added some supporting documents to the post that describe how to construct html tags that send a JSON Post call and how to translate JSON body structure to html structure needed for an email form.

1 Like

I m on a feel now that we are able to create MailChimp kinda of clone (not a clone but html email module) inside Appsheet app.
I just did a quick test to generate html email body but simple tag seems to be ignored.
And other html tag such as was not work neither, so overall, there is some restrictions to generate fancy html output for now.
To make the html decoration easier, it would be easier to use Bootstrap or other css framework using element , but it seems to be impossible for the moment.

1 Like

Thank you very much @Rich
This reminds me of @LeventK’s tip.

… and mine

But I like your solution, because it does not open a site in the browser, which is taking some seconds.
Your solution seems to be faster to the user.


Thanks @Fabian for pointing those posts out too. Ill reference them in the above post as well. @LeventK


When you click on the “Keygap for Approver from Email” it’s redirecting to Simple Inventory Manager.

sorry about that, I had temporarily disabled it as a sample app. It should be viewable now.

1 Like

Great solution! I put it to use right away!

Is there a way to avoid other users triggering the action if the e-mail containing the button is copied or forwarded to someone that’s not supposed to trigger it? Perhaps capturing the e-mail of who clicked it?

This is amazing! Is there a way we can return the email metadata like the Message ID back using any work around ?

You could add a pin number to the process when submitting the form. You can have it so users can setup a pin in the app itself or some other thing they the approver “knows” and then require it when clicking approve.

I don’t think you can do this without writing code and creating a gmail add on.

Hi @Rich thank you for this amazing TIPS.