Gmail OAuth errors

The most common issues when connecting Gmail, and what actually causes each one.

"accessNotConfigured" / "SERVICE_DISABLED"

Cause: the connection itself succeeded, but the Gmail API isn't enabled on your Google Cloud project.

Fix: in Google Cloud Console, go to APIs & Services → Library, search Gmail API, and click Enable. This is the single most common thing missed during Gmail setup — the OAuth app can be fully configured and still fail here if this one step is skipped.

Google's own guide for enabling an API from the Library: Enable and disable APIs.

"error=access_denied" on the callback

Cause: you (or the Google account you signed in with) declined the consent screen, or that account wasn't added as a test user while the app is in Testing mode.

Fix: retry and accept every permission on the consent screen. If it's rejected before you even see a consent screen, confirm the Gmail address you're connecting is listed under OAuth consent screen → Test users.

"redirect_uri_mismatch"

Cause: the redirect URI Google receives doesn't exactly match what's registered on the OAuth client.

Fix: in Google Cloud Console, confirm Authorized redirect URIs contains exactly https://your-domain.com/oauth/google/callback — matching scheme, domain, and path precisely, no trailing slash.

"Google hasn't verified this app"

Cause: this is expected, not an error. A Testing-mode OAuth app always shows this warning to its test users.

Fix: nothing needs fixing — click Advanced → Go to [app name] (unsafe) to proceed. See BYOC, explained for why staying in Testing mode is the intended setup, not a workaround.

400 "invalid_grant" from oauth2.googleapis.com/token (account worked, then suddenly fails)

Cause: your Google Cloud OAuth client is in Testing publishing status — the default, recommended setup in step 2 of Connect Gmail. Google enforces a hard rule on every Testing-mode app: refresh tokens it issues expire after exactly 7 days, unconditionally — it doesn't matter how often the account sends. Once that clock runs out, SubsiMail's next attempt to refresh the access token gets rejected with 400 invalid_grant, and the account shows as disconnected until it's reconnected from the Accounts page.

Straight from Google's own docs: OAuth app state overview — "the 100-test-user cap and the 7-day refresh token expiration limit for apps in the Testing status."

Fix: this isn't something SubsiMail's code can work around — it's Google invalidating the token on their end. Three real options, in order of how most users actually resolve it:

  • Switch this account to SMTP/IMAP with a Gmail App Password. Requires 2-Step Verification on the Google account, then a 16-character App Password works with smtp.gmail.com:587 and imap.gmail.com:993 for both sending and stop-on-reply detection — entirely outside Google's OAuth API, so the 7-day limit (and Testing/Production status generally) simply doesn't apply. This is what most people land on for unattended, long-running campaigns. See Connect via SMTP/IMAP.
  • Reconnect weekly. Click Reconnect on the Accounts page each time this happens. Workable for light or short-term use, not realistic for campaigns you want to run hands-off.
  • Publish the OAuth app to Production. Removes the 7-day limit entirely, but SubsiMail requests the gmail.readonly scope (for stop-on-reply and Read Latest Email), which Google classifies as restricted — publishing with a restricted scope requires a paid, annually-renewed CASA security audit (roughly $500–$4,500/yr). In BYOC that cost is yours, not SubsiMail's, since you own the Google Cloud project.