Documentation

✉️ Email Delivery

Documentation, reference material and tutorials for CRM-NG SMTP Email: setup guides for every mail service, troubleshooting, and one article per error message.

Error: invalid_grant: token expired or revoked (Gmail)

Updated

By Duane GarnerChief Executive Officer (CEO)
Summarize: Claude ChatGPT View Markdown
On this page

Google no longer accepts the saved Gmail connection. Find out why the token stopped working and reconnect the Google account.

This article is for sites that send with the Google / Gmail mailer and see a failed send that mentions invalid_grant together with "expired" or "revoked".

The error as you see it

invalid_grant: Token has been expired or revoked.

Shown by the Google / Gmail mailer, in the failed-send banner, in Tools → Debug Events and in the Email Log.

What this error means

When you press Allow plugin to send emails using your Google account, Google gives the plugin a long-lived refresh token. Every time your site sends, the plugin trades that refresh token for a short-lived access token. This error means Google refused the trade: the refresh token is no longer valid. Nothing is wrong with your Client ID or Client Secret as such; the permission the Google account gave has ended, and the account must authorize again.

Common causes

  • The OAuth app is still in "Testing". Google expires refresh tokens after about seven days for apps whose publishing status is Testing. Mail works for a week, then stops. This is the most common cause.
  • Someone removed the app's access from the Google account's security settings, or a Google Workspace admin revoked it.
  • The Google account password was changed or reset. Google revokes tokens with Gmail scopes when the password changes.
  • The token was not used for about six months, so Google retired it.
  • Too many authorizations. Google keeps a limited number of refresh tokens per account and app. If you reconnected many times (for example on several staging copies), the oldest tokens are silently dropped.
  • The site was cloned. A staging copy that reconnects with the same Google account can push the live site's token out.

How to fix

  1. Open the Google Cloud Console

    Go to https://console.cloud.google.com/, sign in, and select the project that holds the OAuth client used by this site.

  2. Check the publishing status

    Open the OAuth consent screen settings (the console currently lists them under Google Auth Platform → Audience; older consoles show APIs & Services → OAuth consent screen). If the status is Testing and the user type is External, choose Publish app so it is In production. For a Google Workspace account you can set the user type to Internal instead, which has no seven-day limit.

  3. Check the account's connections

    Signed in as the sending Google account, open https://myaccount.google.com/permissions and look for your app. If it is missing, access was revoked; that is fine, you will grant it again below.

  4. Remove the old connection in CRM-NG SMTP

    In WordPress go to CRM-NG SMTP → Settings → General. Under Authorization, press Remove OAuth Connection.

  5. Authorize again

    Press Allow plugin to send emails using your Google account, choose the sending account, and approve the request. You return to the settings page, which now shows Connected as with the account address.

  6. Send a test

    Go to CRM-NG SMTP → Tools → Email Test, enter an address in Send To and press Send Email.

Verify it worked

The test page shows "Test email sent successfully! Check your inbox to confirm delivery." and the message arrives. If you fixed a Testing status, the real proof is that mail still goes out a week from now; keep an eye on Tools → Debug Events for new invalid_grant entries.

Notes

  • Publishing an External app that only asks for the gmail.send scope may show a "Google hasn't verified this app" screen during authorization. As the owner of both the app and the account, you can continue past it.
  • Use a separate OAuth client for staging copies, so a test site never invalidates the live site's token.
  • If the error says invalid_grant but mentions "Bad Request" rather than expiry, see invalid_grant: bad request.
Go to Top