nopSolutions/nopCommerce · error · NopException

Admin.Configuration.EmailAccounts.Fields.ClientId.Required

Error message

Admin.Configuration.EmailAccounts.Fields.ClientId.Required

What it means

Thrown by SmtpBuilder.GetGmailCredentialsAsync when building Gmail OAuth2 (SASL) credentials for an EmailAccount. Gmail OAuth requires a ClientId; if EmailAccount.ClientId is empty, the OAuth flow cannot start, so it throws a NopException whose message is a localized admin resource key. This is a configuration-completeness check before contacting Google.

Source

Thrown at src/Libraries/Nop.Services/Messages/SmtpBuilder.cs:53

        ILocalizationService localizationService,
        INopFileProvider fileProvider)
    {
        _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)
        });

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. In admin (Configuration > Email accounts), open the account and set the ClientId from the Google Cloud OAuth client.
  2. Also set ClientSecret and complete the OAuth consent/authorization flow.
  3. Ensure the email account's host is the Gmail SMTP host and the correct credential fields are populated.
  4. Verify the Google Cloud project has the Gmail SMTP/SCOPE enabled.

Example fix

// before - account created with empty ClientId

// after - set the ClientId in admin, or validate before sending
if (string.IsNullOrEmpty(account.ClientId) || string.IsNullOrEmpty(account.ClientSecret))
    return Error("Complete Gmail OAuth credentials (ClientId + ClientSecret) for this email account.");
Defensive patterns

Strategy: validation

Validate before calling

// Validate Gmail OAuth fields before triggering an SMTP build/send
if (account.Host.Contains("gmail", StringComparison.OrdinalIgnoreCase)
    && string.IsNullOrEmpty(account.ClientId))
    return Error("Set the Gmail OAuth ClientId 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.ClientId.Required"))
{ /* surface a localized 'set ClientId' message to the admin */ }

Prevention

When it happens

Trigger: An EmailAccount configured with the Gmail host/auth scheme but with a blank ClientId field; sending an email via such an account triggers GetGmailCredentialsAsync.

Common situations: Admin created a Gmail OAuth email account but did not paste the Google OAuth ClientId; deploying without copying OAuth credentials; switching an account to Gmail without completing the OAuth setup.

Related errors


AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13). Data as JSON: /api/errors/b707d3428485d587. Report an issue: GitHub.