Dev Zone

ODC Gmail integration: APIs save the day

joao ferreira
hero-bp-gmail-apis-odc

It all started with a requirement that sounded mistakenly simple: our internal portal needed to monitor a specific mailbox, catch new notification emails, and trigger a business workflow based on their content.

Our first thought? “Just use the out-of-the-box SMTP integration available in the ODC Portal!” But, we hit a wall almost immediately.

Standard SMTP is great for email sending, but it falls short for actually interacting with a mailbox. It’s just not designed for reading, organizing threads, or managing the state of an email (like marking it as “read”), not to mention integrating and processing its data on a third-party system.

Gmail APIs came to save the day, allowing our OutSystems app to access the mailbox and treat it like a structured data source. Gmail API is a standard RESTful service that uses JSON payloads. That means that if you’re used to consuming REST APIs in OutSystems, you’re already in the middle of the path.

You can not only send emails but also list threads, which means you can fetch entire conversation history. You can also get the full details of a message and metadata with full granularity, so you don’t need to fetch the entire message to access a specific header. And you can manage labels (“labels” is the term for folders in Gmail).

As developers with some experience performing server-side integrations, our default option is an approach relying on a Service Account. We want a backend process to read emails without user interaction. A Service Account (2-legged OAuth) uses a JWT (JSON Web Token) to authenticate directly with Google, bypassing the browser entirely. It works like a charm for a headless automation!

But here is the trap!

A Service Account is a “non-human user” in practice, but it cannot just simply “log in” to your personal work email or a shared support@company.com inbox. To make it work for us, our use case, and make a Service Account read real user emails, we would have to enable Domain-Wide Delegation. This grants the Service Account the authority to impersonate any user in our entire Google Workspace, which is a security risk. For example, on a key leak, an attacker could read the CEO’s email. We would also need a G-Suite Super Admin to set this up (good luck with that).

The solution was to choose the standard 3-Legged OAuth flow, which involves three parties (legs):

  1. The Resource Owner (the user).
  2. The client (our OutSystems App).
  3. The Authorization Server (Google)

And of course we thought that this would not be the perfect solution as this requires a user to log in and we were looking for an automated flow. Nevertheless, the magic technical component for this approach is Offline Access.

When we initiate the OAuth flow, we explicitly request access_type=offline.

  1. First run: A human logs in once via the browser consent screen.
  2. The exchange: Google returns an Access Token (short-lived) and a Refresh Token (long-lived).
  3. Automation: Your app securely stores the Refresh Token. From that moment on, your timer acts "on behalf of" that user. It presents the Refresh Token to Google to get new Access Tokens in the background, without ever needing a browser or user interaction again.

This approach respects the Principle of Least Privilege. The app only accesses the specific authorized mailbox, only for the scopes defined, and the user can revoke access at any time via their Google Account security settings. No Super Admin required.

The setup: Google Cloud Console

Yeah, you know, there’s always some config we have to do first when working with integration, right? In this case, that’s on Google Cloud Console and that’ll allow your OutSystems app to connect to your Gmail account.

Project creation

You need a project in GCP.

OAuth consent screen

This is the "face" of your app.

Dev Tip: If your app is in "Testing" status, you must add specific test user emails, or the login will fail with a 403.

Credentials

Creating the Client ID and Client Secret.

Critical configs:

  • Redirect URIs: This must exactly match your OutSystems URL (https://.../Callback). A trailing slash or http/https mismatch breaks everything.
  • Scope: They are the API permissions strings. For this feature to work, you’re going to need at least “gmail.readonly” scope and that’s what we want, to always work with the principle of the least privilege, remember (come on, we just talked about that)?

Implementation in OutSystems (the "how-to")

In this section, we will finally handle the app creation on the OutSystems side and you’ll see that once the setup is done on GCC (Google Cloud Console) it’s kinda straightforward.

The auth flow

  • Redirect: Construct the URL (auth endpoint + client_id + scopes + redirect_uri) and send the user away.
  • The Callback: The user comes back with a code (Authorization Code).
  • The Exchange: Your server (Server Action) swaps the code for an access_token and refresh_token.

Handling tokens

  • Access Token: Short-lived (1 hour). Use it for API calls.
  • Refresh Token: Long-lived. SAVE THIS. This is how you stay logged in next week without asking the user again.
  • Pro-Tip: If you lose the Refresh Token, you have to force the user to re-consent (use prompt=consent).

Calling the APIs

  • Headers: Authorization: Bearer <Access_Token>
  • Structure: GET /users/me/messages -> Returns a list of IDs (lightweight)
    GET /users/me/messages/{id} -> Returns the heavy payload (body, headers).
  • Performance Tip: Gmail API separates "Listing" from "Retrieving details" to save bandwidth. Don't fetch details for 100 emails in a loop on the foreground!

Conclusion

What began as a simple requirement for reading emails turned into a great opportunity for technical exploration. Learning how to interact with the Gmail APIs was challenging at first, and it took considerable time. However, in the end it created and revealed a fulfilling learning opportunity. What was even better was the sense of accomplishment that came with sharing this with the community.

The GmailExplorer Reactive app encapsulates much of the logic we try to explain in this article. Give it a spin and if you have questions, as always, reach out to us. (The app itself has a link for you to book a meeting directly with us - just click on the Talk to an Expert link.)