A hands-on walkthrough of the Gmail activities in the Google Workspace SDK, built into a single task automation and tested against real emails.
Introduction
This is the fifth post in the series. In the previous post, we set up the Google OAuth client, created the External Authentication in Control Tower, registered it on the Desktop Agent, and built a small automation that searches Gmail and saves attachments to a local folder. That post ended with one search, one read, and a folder of PDFs.
Gmail offers a lot more than that. In this post we go through every Gmail activity BPA provides, one at a time, inside a single task automation. Along the way we make sure an email is never read twice, send a fresh email with attachments, reply to a thread, and finally delete an email.
Here’s what we’ll cover:
- Searching Gmail and reading an email, with its attachments saved to a local folder
- Moving a processed email from Inbox to a “read” label, so it’s never fetched again
- Sending an email with attachments
- Replying and replying to all on an existing thread
- Deleting an email (and why that one deserves extra care)
- Cleaning up with Disconnect (Google)
The Gmail Activities at a Glance
With the Google Workspace SDK added to the project, searching for “Gmail” in the automation’s Tools panel lists seven activities: Send Email, Search Emails, Read Email, Modify Email Labels, Send Reply, Reply All and Delete Email. It also lists the supporting data types, such as Gmail Attachments, Gmail Message Detail, Gmail Message Identifier, Gmail Parameters and Gmail Reply Parameters. Every activity we use in this post is highlighted below in red.
The finished automation with each Gmail activity highlighted, next to the Gmail activities in the Tools panel.
The flow reads top to bottom, and each group of steps maps to one part of this post:
- Steps 3 to 6: search the inbox, check that something was found, empty the target folder, and read the email with its attachments.
- Step 7: modify the labels on the email we just read.
- Step 8: send a new email with attachments.
- Steps 10 to 12: search for a thread, then reply to all and reply to it.
- Steps 13 and 14: search for a temporary email and delete it.
- Step 15: disconnect from Google.
Everything from step 1 (Select Google Authentication) sits inside the same Try / Catch pattern from the previous post, catching GmailError.
Before You Start
- The External Authentication from the previous post needs the Gmail scope. That scope covers reading, sending and permanently deleting email, so nothing extra is needed for this post. If you ever add a scope, update the External Authentication in Control Tower and register it on the Desktop Agent again.
- Create a Gmail label named BPA-Read manually in Gmail. The automation applies this label but does not create it.
- Prepare three test emails with distinct subjects, so each part of the flow only touches its own email: Gmail-BPA (with three PDF attachments) for read and label, BPA-Gmail (a thread with a few participants) for the reply steps, and BPA-Delete for the delete step.
- Use a test mailbox. The delete step is permanent.
Part 1: Search and Read an Email
This part repeats the idea from the previous post, so I’ll keep it brief. The test email sits in the Inbox, with the subject Gmail-BPA and three invoice PDFs attached.
The test email in the Inbox, with three PDF attachments.
- Search Emails (Gmail). I renamed this step “Search Emails (Gmail) for Read & Get Attachments” so it’s easy to tell apart from the other searches later in the flow. The query is Label: Inbox subject:(“Gmail-BPA”), so only emails still in the Inbox with that subject are returned. includeSpamTrash is false, and the output, messageIdentifiers, is the list of matches.
Search Emails (Gmail) for Read & Get Attachments.
- Email Found? A Condition step checks Step3.messageIdentifiers.length > 0. If nothing matches, the default branch just logs a message.
The Email Found? condition.
- Delete All Files. Before downloading, this empties the local target folder, so files from an earlier run are never picked up again.
Delete All Files on the target folder.
- Read Email (Gmail). messageId is messageIdentifiers[0].messageId, location is fileSystem, and pathOrDriveId is the same target folder. The three PDFs are saved there, and the output messageDetail holds the email details.
Read Email (Gmail) saving the three attachments into the target folder.
Part 2: Modify Email Labels
Here is a problem with the flow so far: the email stays in the Inbox after we read it, so the next run would find and read it again. We solve that with Modify Email Labels (Gmail), which moves the email out of the Inbox and into our BPA-Read label. Because the search query includes Label: Inbox, an email that has been moved never matches again.
- Modify Email Labels (Gmail). messageId is messageIdentifiers[0].messageId, the same email we just read. labelsToAdd is a list holding BPA-Read, and labelsToRemove is a list holding Inbox. Both lists are entered as custom data, one string per label.
Modify Email Labels (Gmail) adding BPA-Read and removing Inbox.
Back in Gmail, the same email now carries the BPA-Read label instead of Inbox.
The processed email, now labelled BPA-Read.
This is the label approach I chose over the markAsRead option on Read Email. The email keeps its read or unread state, and the label gives you a visible record of what the automation has handled, which you can also search on in Gmail.
Part 3: Send Email
Next we send a new email using Send Email (Gmail). All its inputs live in one custom data object called gmailParameters.
- Fill in the recipient fields: to, plus optional cc and bcc (semicolon separated). I sent it to my own address for the test.
- Set the subject ([BPA Auto] Invoice Attachments | Send Mail) and the body. isHtmlBody is false here, so the body is plain text. Set it to true if you want to send HTML.
Send Email (Gmail) — recipients, subject, body and the start of the attachments list.
- Add attachments. Each attachment is its own entry with attachFrom (fileSystem here) and a filePath. I attached the same three PDFs we downloaded in Part 1, purely for convenience. Any file path works, so you can attach whatever your scenario needs.
One attachment entry per file, each with attachFrom and filePath.
The email arrives with all three PDFs attached.
The email sent by the automation, with its three attachments.
Part 4: Reply and Reply All
To reply to an existing conversation, the automation needs to know which thread to reply into. For this I set up a separate test thread with a few participants, subject BPA-Gmail, and added a dedicated search step for it.
- Search Emails (Gmail) To Reply. The query is Label: Inbox subject:(“BPA-Gmail”), and the output is again messageIdentifiers, this time from step 10.
Search Emails (Gmail) To Reply.
- Reply All (Gmail). The input is replyParamters (the spelling as it appears in the activity). threadId is messageIdentifiers[0].threadId from step 10, which is what places the reply inside the existing conversation. messageId, to, cc and bcc are left empty, and the body is the text to send. includeOriginalAttachments is false, and attachments can be added the same way as in Send Email.
Reply All (Gmail), with threadId taken from the search step.
- Send Reply (Gmail). It has the same parameters as Reply All. The difference is in who receives the message: Reply All goes to everyone on the thread, while Send Reply goes back to a single recipient.
Send Reply (Gmail), with the same parameter structure.
In Gmail, both messages show up inside the original thread. In my test, the Reply All message went to all four other participants, and the Reply went to one.
The test thread, with the Reply All and Reply messages sent by the automation at the bottom.
Part 5: Delete Email
The last activity is Delete Email (Gmail). As with replying, we first find the email, this time using a dedicated search step with the subject BPA-Delete.
- Search Emails (Gmail) To Delete. The query is Label: Inbox subject:(“BPA-Delete”), and the output messageIdentifiers comes from step 13.
Search Emails (Gmail) To Delete.
- Delete Email (Gmail). The only required input is messageId, here messageIdentifiers[0].messageId from step 13.
Delete Email (Gmail) with the messageId from the search step.
This is the temporary email the automation removes:
The temporary email, before the automation runs.
This deletion is permanent. When you delete an email in the Gmail interface, it moves to Trash and is removed later, either after Gmail’s retention period or when you empty the Trash yourself. The Delete Email activity does not do that. In my test the email was gone immediately and did not appear in Trash, which matches how Google describes the underlying delete call in the Gmail API: immediate and permanent, with no way to undo it. Treat this activity like a delete statement without a rollback.
Finishing Up: Disconnect (Google)
The last step of the flow, step 15, is Disconnect (Google), which closes the connection to Google once the work is done. It sits after the Try / Catch block, so it runs on both the success and error paths.
Things to Keep in Mind
- Be careful with delete. Use a precise query (here, a keyword unique to the temporary email), run it against a test mailbox first, and consider whether a label like BPA-Delete or a separate review step is safer for production scenarios.
- Guard the later steps. In this flow, steps 10 to 14 sit outside the Email Found? condition, and they read messageIdentifiers[0]. If a search returns no results, that step has nothing to read. Wrapping each search-then-act pair in its own condition, like we did for step 4, avoids that.
- First match only. Using index 0 means each run handles one email per search. For several emails, loop over messageIdentifiers.
- Labels must exist. Modify Email Labels uses the label names you enter, so create BPA-Read in Gmail first and keep the spelling identical.
- Gmail search syntax. The query field accepts the same operators as the Gmail search bar, so you can narrow results further (for example, by sender or date).
- Testing-mode token expiry. As noted in the previous post, an External app in Testing status has a limited refresh token lifetime. If authorization suddenly fails after about a week, register the authentication on the Desktop Agent again.
Wrapping Up
With these seven activities, a BPA automation can do nearly everything you’d do by hand in a Gmail inbox: find an email, read it and save its attachments, mark it as processed, send a new message, reply into a thread, and, when needed, delete one for good. They all run on the single setup from the previous post.
If you want to take this further into a complete invoice flow, you can combine the pieces from this series yourself. Each post covers one layer: the first builds the invoice approval process, the second sets up Document AI extraction on a trial instance, the third wires extraction into the approval process, and the fourth connects BPA to Google Workspace and fetches the attachments. This post adds the remaining Gmail activities on top of that setup. The fetched PDFs from the Gmail steps can serve as the source folder for the extraction automation in the second and third posts.
Each part is covered and tested on its own, and the connection points (a folder of PDFs, then extraction, then a call to the approval process) are the same ones those posts already use. If you would like the decision to go back to the sender as a reply in the original email thread, the Send Reply and Reply All activities are the ones to look at. The approval emails in the earlier posts are sent from the process itself, so that part would need some extra wiring.
Read More Technology Blog Posts by Members articles
#abap