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):
- The Resource Owner (the user).
- The client (our OutSystems App).
- 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.
- First run: A human logs in once via the browser consent screen.
- The exchange: Google returns an Access Token (short-lived) and a Refresh Token (long-lived).
- 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.)