Google OAuth Token drops after 1h & sending emails from templates fails (HTTP 200)

Hi everyone,

I am currently battling a combination of Google Workspace OAuth issues and failing email sends from templates in SuiteCRM 8. I managed to solve the token drop issue via core patches, but I are currently stuck on the email sending issue. Here is my detailed breakdown:

:laptop: System Environment

  • SuiteCRM 8.7.1

  • Connection via Google Workspace (OAuth2)

  • Cronjobs running via CLI (www-data)


:police_car_light: Problem 1: The 1-Hour Google API Token Drop (SOLVED)

Symptom: The Google API Token synchronization lost authorization exactly after 60 minutes (when the Access Token expires). The checkbox for “Enable Calendar Synchronization” in the user profile was automatically unchecked.

Root Cause Analysis & Fix:

  1. Missing Refresh Token (Consent): SuiteCRM did not enforce user consent when generating the Google Auth URL. As a result, Google didn’t issue a new refresh_token during re-authorization.

  2. Missing Mail Scope: The button only requested the Calendar scope, but not mail.google.com.

  3. Core Bug in setPreference: In GoogleSyncBase.php (line 126), the method $this->workingUser->setPreference(...) was missing the 3rd parameter $is_session = false. Because of this, the renewed token was only saved to the volatile session and never actually written to the database.

Applied Code Patch: We modified the following two files:

File 1: public/legacy/modules/Users/GoogleApiKeySaverEntryPoint.php

PHP

// Expanded scopes and added consent/force prompt (around line 91)
$this->client->setScopes(array(Google\Service\Calendar::CALENDAR, 'https://mail.google.com/'));
// ...
$this->client->setAccessType('offline');
$this->client->setPrompt('consent');
$this->client->setApprovalPrompt('force');

File 2: public/legacy/include/GoogleSync/GoogleSyncBase.php

PHP

// Added the missing 'false' as 3rd parameter in getGoogleClient() (line 126)
$this->workingUser->setPreference('GoogleApiToken', base64_encode(json_encode($client->getAccessToken())), false, 'GoogleSync');

Result: The Re-Authorize flow now requests the correct scopes and the refresh token is permanently written to the DB. The cronjob survives the 1-hour mark without dropping the connection.


:police_car_light: Problem 2: Email sending from templates fails (UNSOLVED)

Symptom: Sending the System Test Email from the Admin panel works perfectly. However, if a user tries to send an email via the CRM (ComposeView in the Emails module) using an Email Template, the process aborts. The UI only displays a generic popup: “Error sending email. Please contact your administrator.”

What we have analyzed so far:

  • Network Tab (F12): The POST request (action=send, module=Emails, ComposeView) returns an HTTP Status 200 OK, but the email doesn’t go out and the UI throws the error. There is no JSON error message visible in the response body.

  • Template Check: Tested templates with and without attachments. Tested templates with and without variables (e.g., $account_name). “From Name” and “From Address” in the template were completely cleared to avoid identity mismatch/spoofing rejections by Google. No success.

  • Logs: The suitecrm.log shows no FATAL or ERROR entries regarding SMTP or emails during the send attempt. It only shows the known Suite8 bug (Bean file does not exist in path: modules/Users/User.php), which shouldn’t be related to the email dispatch.

  • Mail Accounts: The Google API Token status in the user profile shows CONFIGURED.

Our question for the community: Where exactly does the legacy Email module (ComposeView) hide the actual PHP/SMTP error message when it returns a Status 200, but the UI throws the generic popup? Could this be a routing issue regarding the user’s outbound mail server settings (OAuth2 Token vs. Basic Auth)?

Any hints on how to further isolate this issue would be greatly appreciated!

The 1-hour token expiry is a known pain point with Google’s OAuth for server-side apps. Your core patch to refresh the token is the right approach, but the email template issue is likely a separate problem.

For the template send failing with HTTP 200 but no email actually going out, check the SuiteCRM log at suitecrm.log for the actual SMTP response. A 200 from the UI just means the request was accepted, not that the email was delivered. Common causes:

  1. The template variables might not be resolving correctly when sent via the API vs the compose screen. Test by sending a template with no variables first to isolate whether it is a variable resolution issue or a sending issue.

  2. If you patched the OAuth token refresh in the core, make sure the refreshed token is also being picked up by the email sending module. Sometimes the outbound email config caches the old token in the session.

  3. Check if the Google API scope includes https://mail.google.com/ (full access) vs just https://www.googleapis.com/auth/gmail.send. The send scope alone can behave differently with templates that include attachments or inline images.