nopSolutions/nopCommerce · error · NopException
Admin.Configuration.EmailAccounts.Fields.ClientSecret.Requir
Error message
Admin.Configuration.EmailAccounts.Fields.ClientSecret.Required
What it means
Thrown by SmtpBuilder.GetGmailCredentialsAsync when EmailAccount.ClientSecret is empty for a Gmail OAuth account. OAuth requires the client secret to exchange the auth code for tokens; without it the flow fails immediately, so it throws NopException with a localized resource message. It is the companion check to the ClientId validation.
Source
Thrown at src/Libraries/Nop.Services/Messages/SmtpBuilder.cs:56
_emailAccountSettings = emailAccountSettings;
_emailAccountService = emailAccountService;
_localizationService = localizationService;
_fileProvider = fileProvider;
}
#endregion
#region Utilities
protected virtual async Task<SaslMechanism> GetGmailCredentialsAsync(EmailAccount emailAccount)
{
ArgumentNullException.ThrowIfNull(emailAccount);
if (string.IsNullOrEmpty(emailAccount.ClientId))
throw new NopException(await _localizationService.GetResourceAsync("Admin.Configuration.EmailAccounts.Fields.ClientId.Required"));
if (string.IsNullOrEmpty(emailAccount.ClientSecret))
throw new NopException(await _localizationService.GetResourceAsync("Admin.Configuration.EmailAccounts.Fields.ClientSecret.Required"));
var tokenFilePath = _fileProvider.MapPath(NopMessageDefaults.GmailAuthStorePath);
var credentialRoot = _fileProvider.Combine(tokenFilePath, emailAccount.Email);
var codeFlow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = emailAccount.ClientId,
ClientSecret = emailAccount.ClientSecret
},
Scopes = NopMessageDefaults.GmailScopes,
DataStore = new FileDataStore(credentialRoot, true)
});
var authCode = new AuthorizationCodeWebApp(codeFlow, null, null);
var authResult = await authCode.AuthorizeAsync(emailAccount.Email, CancellationToken.None);View on GitHub (pinned to 64bdf2ff08)
Solutions
- In admin, set the EmailAccount ClientSecret from the Google Cloud OAuth client.
- Re-run the OAuth authorization so a token store is created with valid credentials.
- Confirm both ClientId and ClientSecret are non-empty before marking the account active.
- Ensure the Google OAuth client type is 'Desktop'/'Web' with the secret available.
Example fix
// before - only ClientId set
// after - require both before the account can send
if (string.IsNullOrEmpty(account.ClientId) || string.IsNullOrEmpty(account.ClientSecret))
return Error("Gmail OAuth requires both ClientId and ClientSecret."); Defensive patterns
Strategy: validation
Validate before calling
if (account.Host.Contains("gmail", StringComparison.OrdinalIgnoreCase)
&& string.IsNullOrEmpty(account.ClientSecret))
return Error("Set the Gmail OAuth ClientSecret for this email account."); Type guard
static bool HasGmailCredentials(EmailAccount a)
=> !string.IsNullOrEmpty(a.ClientId) && !string.IsNullOrEmpty(a.ClientSecret); Try / catch
try { await smtpBuilder.BuildAsync(account); }
catch (NopException ex) when (ex.Message.Contains("EmailAccounts.Fields.ClientSecret.Required"))
{ /* surface a localized 'set ClientSecret' message to the admin */ } Prevention
- Store the Google client secret securely and paste it into the account.
- Re-authorize after rotating the OAuth client secret.
- Validate both OAuth fields together when saving.
When it happens
Trigger: A Gmail-configured EmailAccount with a populated ClientId but blank ClientSecret; sending mail triggers GetGmailCredentialsAsync.
Common situations: Admin pasted only the ClientId; OAuth client secret not copied from Google Cloud; redeploy without the secret in config.
Related errors
- Admin.Configuration.EmailAccounts.Fields.ClientId.Required
- Failed to obtain user credentials for the authorization serv
- Admin.Configuration.EmailAccounts.Fields.TenantId.Required
- Email account could not be loaded
- Client ID is not set
AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13).
Data as JSON: /api/errors/ddccf6a0d92f9388.
Report an issue: GitHub.