SonarSource/sonarqube · warning

Failed to send quality gate change email notification for…

Error message

Failed to send quality gate change email notification for project {}

What it means

EmailQGChangeEventListener reacts to Quality Gate status change events by sending notification emails. If notifyUsers throws for any reason (SMTP problems, missing project/branch data, template rendering errors), the listener logs this warning with the project key and continues, so notification failure never breaks the compute engine event pipeline.

Solutions

  1. Check the logged exception for the root cause (stack trace follows the project key).
  2. Verify email settings (smtp.host, smtp.port, smtp.username/password) in sonar.properties and test connectivity to the SMTP server.
  3. Confirm the project and branch still exist and users' notification subscriptions resolve to valid email addresses.
  4. Re-run the analysis if the notification was critical; the event itself succeeded.

Example fix

// before: unreachable SMTP
sonar.email.smtp.host=mail.internal.example.com
sonar.email.smtp.port=25
// after: corrected reachable SMTP with auth
sonar.email.smtp.host=smtp.example.com
sonar.email.smtp.port=587
sonar.email.smtp.username=sonar@example.com
sonar.email.smtp.secure.connection=STARTTLS
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check SMTP reachability before enabling QG notifications
const net = require('net');
const s = net.createConnection(587, 'smtp.example.com');
s.on('connect', () => { console.log('SMTP reachable'); s.end(); });

Try / catch

try {
  await mailer.send(qgChangeEmail);
} catch (e) {
  logger.warn('Failed to send quality gate change email notification for project ' + projectKey, e);
  // never rethrow: notifications must not break analysis pipeline
}

Prevention

When it happens

Trigger: onIssueChanges -> notifyUsers raising an exception while building or sending the quality-gate-change email for the event's project (e.g. mail server unreachable, no recipients resolved, persistence lookup failure on project/branch DTOs).

Common situations: SMTP host misconfigured or down; mail credentials rejected; project deleted between event creation and notification; corrupted branch data; permission/credential lookup failures for subscribed users.

Related errors


AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/a9eb18b77826bf72. Report an issue: GitHub.

Appendix: source

Thrown at server/sonar-webserver-core/src/main/java/org/sonar/server/qualitygate/notification/EmailQGChangeEventListener.java:74

  @Override
  public void onIssueChanges(QGChangeEvent event, Set<ChangedIssue> changedIssues) {
    Optional<EvaluatedQualityGate> evaluatedQG = event.getQualityGateSupplier().get();
    if (evaluatedQG.isEmpty()) {
      return;
    }

    Metric.Level newStatus = evaluatedQG.get().getStatus();
    Optional<Metric.Level> previousStatus = event.getPreviousStatus();

    if (previousStatus.isPresent() && previousStatus.get() == newStatus) {
      return;
    }

    try {
      notifyUsers(event, newStatus, previousStatus.orElse(null));
    } catch (Exception e) {
      LOGGER.warn("Failed to send quality gate change email notification for project {}", event.getProject().getKey(), e);
    }
  }

  private void notifyUsers(QGChangeEvent event, Metric.Level newStatus, @Nullable Metric.Level previousStatus) {
    ProjectDto project = event.getProject();
    BranchDto branch = event.getBranch();
    EvaluatedQualityGate evaluatedQG = event.getQualityGateSupplier().get().orElseThrow();

    String statusLabel = toStatusLabel(newStatus);
    boolean isNewAlert = previousStatus == null;

    try (DbSession dbSession = dbClient.openSession(false)) {
      Map<String, MetricDto> metricsByKey = dbClient.metricDao().selectAll(dbSession).stream()
        .collect(Collectors.toMap(MetricDto::getKey, Function.identity()));

      String alertText = conditionFormatter.buildAlertText(evaluatedQG, metricKey -> {
        MetricDto metric = metricsByKey.get(metricKey);
        return new QualityGateConditionFormatter.MetricInfo(

View on GitHub (pinned to 184c821202)