{"record":{"id":"ddccf6a0d92f9388","repo":"nopSolutions/nopCommerce","slug":"admin-configuration-emailaccounts-fields-clientsec","errorCode":null,"errorMessage":"Admin.Configuration.EmailAccounts.Fields.ClientSecret.Required","messagePattern":"Admin\\.Configuration\\.EmailAccounts\\.Fields\\.ClientSecret\\.Required","errorType":"exception","errorClass":"NopException","httpStatus":null,"severity":"error","filePath":"src/Libraries/Nop.Services/Messages/SmtpBuilder.cs","lineNumber":56,"sourceCode":"        _emailAccountSettings = emailAccountSettings;\n        _emailAccountService = emailAccountService;\n        _localizationService = localizationService;\n        _fileProvider = fileProvider;\n    }\n\n    #endregion\n\n    #region Utilities\n\n    protected virtual async Task<SaslMechanism> GetGmailCredentialsAsync(EmailAccount emailAccount)\n    {\n        ArgumentNullException.ThrowIfNull(emailAccount);\n\n        if (string.IsNullOrEmpty(emailAccount.ClientId))\n            throw new NopException(await _localizationService.GetResourceAsync(\"Admin.Configuration.EmailAccounts.Fields.ClientId.Required\"));\n\n        if (string.IsNullOrEmpty(emailAccount.ClientSecret))\n            throw new NopException(await _localizationService.GetResourceAsync(\"Admin.Configuration.EmailAccounts.Fields.ClientSecret.Required\"));\n\n        var tokenFilePath = _fileProvider.MapPath(NopMessageDefaults.GmailAuthStorePath);\n        var credentialRoot = _fileProvider.Combine(tokenFilePath, emailAccount.Email);\n\n        var codeFlow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer\n        {\n            ClientSecrets = new ClientSecrets\n            {\n                ClientId = emailAccount.ClientId,\n                ClientSecret = emailAccount.ClientSecret\n            },\n            Scopes = NopMessageDefaults.GmailScopes,\n            DataStore = new FileDataStore(credentialRoot, true)\n        });\n\n        var authCode = new AuthorizationCodeWebApp(codeFlow, null, null);\n\n        var authResult = await authCode.AuthorizeAsync(emailAccount.Email, CancellationToken.None);","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/nopSolutions/nopCommerce/blob/64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2/src/Libraries/Nop.Services/Messages/SmtpBuilder.cs#L38-L74","documentation":"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.","triggerScenarios":"A Gmail-configured EmailAccount with a populated ClientId but blank ClientSecret; sending mail triggers GetGmailCredentialsAsync.","commonSituations":"Admin pasted only the ClientId; OAuth client secret not copied from Google Cloud; redeploy without the secret in config.","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."],"exampleFix":"// before - only ClientId set\n\n// after - require both before the account can send\nif (string.IsNullOrEmpty(account.ClientId) || string.IsNullOrEmpty(account.ClientSecret))\n    return Error(\"Gmail OAuth requires both ClientId and ClientSecret.\");","handlingStrategy":"validation","validationCode":"if (account.Host.Contains(\"gmail\", StringComparison.OrdinalIgnoreCase)\n    && string.IsNullOrEmpty(account.ClientSecret))\n    return Error(\"Set the Gmail OAuth ClientSecret for this email account.\");","typeGuard":"static bool HasGmailCredentials(EmailAccount a)\n    => !string.IsNullOrEmpty(a.ClientId) && !string.IsNullOrEmpty(a.ClientSecret);","tryCatchPattern":"try { await smtpBuilder.BuildAsync(account); }\ncatch (NopException ex) when (ex.Message.Contains(\"EmailAccounts.Fields.ClientSecret.Required\"))\n{ /* surface a localized 'set ClientSecret' message to the admin */ }","preventionTips":["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."],"tags":["email","smtp","oauth","gmail","configuration","nopcommerce"],"backgroundTag":null,"analyzedSha":"64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2","analyzedAt":"2026-08-13T21:19:38.062Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}