← blog
Gmail API OAuth2 Netlify Functions Sicurezza

Gmail API + OAuth2: shared mailbox with no real password

How to connect a shared Gmail mailbox to an internal panel — the same experience as tools like Tidio, Front or Help Scout — without anyone, not even whoever writes the code, ever seeing the mailbox's real password.

Two ways to connect to Gmail, and which to pick

Google offers two paths for an app that needs to read/write Gmail on someone else's behalf:

Aspetto / AspectDomain-Wide DelegationOAuth2 app installata / installed app
Needed for Impersonating multiple mailboxes across a whole Workspace domain A single specific mailbox
Requires Service account + accesso admin a Workspace One-time consent from whoever has real access to the mailbox
Drawback Complex setup, elevated privileges Has to be redone if the token is revoked

For a single shared mailbox, installed-app OAuth2 is almost always the right call: no domain-admin privileges, simpler setup.

Setup on Google Cloud Console

  1. Enable the Gmail API on the Google Cloud project
  2. Configure the OAuth consent screen with the gmail.readonly and gmail.send scopes (minimum necessary — avoid broader scopes like gmail.modify unless needed)
  3. Add the address that will give consent as a "test user" — the app stays in Testing mode, no publishing or Google verification needed for internal use
  4. Create a "desktop app" type OAuth client
  5. Run the one-time consent: the app receives a refresh token, not a password

Regola ferrea: nessuna password reale deve mai passare per chat, ticket o codice. È proprio il senso di OAuth: nemmeno chi implementa l'integrazione ha bisogno di vedere la password vera della casella, in nessun momento del processo — solo il refresh token, salvato esclusivamente come variabile d'ambiente lato server.

The three typical Netlify Functions

A complete integration splits into three server-side functions, never in the client bundle:

The 403 caused by one extra character

A 403 error with a seemingly correct refresh token and client ID/secret is almost always a copy-paste issue: a trailing space, a leftover newline, or an invisible character in the environment variable. Always double-check the exact length and content of the variable on Netlify — don't trust the input field, log the string length temporarily if in doubt.

Limite della modalità Testing: un refresh token per un'app "installata" non ha scadenza fissa, ma può essere invalidato se l'utente cambia password, revoca manualmente l'accesso da Google, o se il client OAuth in modalità Testing supera 100 refresh token attivi. In quel caso basta ripetere il consenso una tantum per generarne uno nuovo.

Making an email look like an email, not a panel table row

The HTML body returned by the Gmail API should render with the message's original styling, not be reformatted with the panel's CSS — otherwise the result looks more like a table row than an email. Images embedded via cid: need resolving by fetching the matching attachment and swapping the reference for a URL or data URI before rendering.

Quick checklist

Frequently asked questions

Can you read and reply to a Gmail mailbox without ever knowing the real password?

Yes, with OAuth2: whoever has real access gives one-time consent on Google, and the app receives a refresh token — not a password — that only lives as a server-side environment variable.

Do you need Domain-Wide Delegation to connect a single Gmail mailbox?

No. It's only needed to impersonate multiple mailboxes across a Workspace domain via a service account, with admin access. For a single mailbox, installed-app OAuth2 with one-time consent is enough.

Can a Gmail refresh token expire or stop working?

It has no fixed expiry, but can be invalidated if the user changes password, revokes access, or if the OAuth client in Testing mode exceeds 100 active refresh tokens. Repeating consent generates a new one.

Related article
How I rebuilt the Tidio experience — with all the real bugs along the way

When to use OAuth2 for a shared Gmail mailbox

This guide shows how to connect a shared Gmail mailbox to an internal panel via server-side OAuth2, without ever handling the account's real password, managing scopes and refresh tokens.

When to use it

When NOT to use it

Alternatives

Common mistakes