Add failure analysis for missing auto-configured MailSender

Signed-off-by: MJY <jmoon0227@gmail.com>

See gh-49582
This commit is contained in:
MJY
2026-03-13 12:02:08 +00:00
committed by Andy Wilkinson
parent 2dca98547b
commit ffb36cb5ed
3 changed files with 162 additions and 0 deletions
@@ -0,0 +1,77 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.mail.autoconfigure;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment;
import org.springframework.mail.MailSender;
/**
* An {@link AbstractFailureAnalyzer} that improves missing {@link MailSender} guidance
* when mail auto-configuration is present but not activated.
*/
class NoSuchMailSenderBeanFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchBeanDefinitionException>
implements Ordered {
private static final String MAIL_HOST_PROPERTY = "spring.mail.host";
private static final String MAIL_JNDI_NAME_PROPERTY = "spring.mail.jndi-name";
private final @Nullable Environment environment;
NoSuchMailSenderBeanFailureAnalyzer(@Nullable Environment environment) {
this.environment = environment;
}
@Override
protected @Nullable FailureAnalysis analyze(Throwable rootFailure, NoSuchBeanDefinitionException cause) {
if (!isMissingMailSenderBean(cause) || hasMailConfigurationProperty()) {
return null;
}
String description = "A MailSender bean could not be found because Spring Boot mail auto-configuration "
+ "did not match. Neither '" + MAIL_HOST_PROPERTY + "' nor '" + MAIL_JNDI_NAME_PROPERTY
+ "' is configured.";
String action = "Consider configuring '" + MAIL_HOST_PROPERTY + "' or '" + MAIL_JNDI_NAME_PROPERTY
+ "' to enable auto-configuration. If you want to use a custom mail sender, define a MailSender "
+ "bean in your configuration.";
return new FailureAnalysis(description, action, cause);
}
private boolean isMissingMailSenderBean(NoSuchBeanDefinitionException cause) {
Class<?> beanType = cause.getBeanType();
if (beanType == null && cause.getResolvableType() != null) {
beanType = cause.getResolvableType().resolve();
}
return (beanType != null) && MailSender.class.isAssignableFrom(beanType);
}
private boolean hasMailConfigurationProperty() {
return this.environment != null && (this.environment.containsProperty(MAIL_HOST_PROPERTY)
|| this.environment.containsProperty(MAIL_JNDI_NAME_PROPERTY));
}
@Override
public int getOrder() {
return 0;
}
}
@@ -0,0 +1,3 @@
# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.mail.autoconfigure.NoSuchMailSenderBeanFailureAnalyzer
@@ -0,0 +1,82 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.mail.autoconfigure;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.diagnostics.FailureAnalysis;
import org.springframework.core.env.Environment;
import org.springframework.mail.MailSender;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link NoSuchMailSenderBeanFailureAnalyzer}.
*/
class NoSuchMailSenderBeanFailureAnalyzerTests {
@Test
void analyzeWhenNotNoSuchBeanDefinitionExceptionShouldReturnNull() {
assertThat(new NoSuchMailSenderBeanFailureAnalyzer(null).analyze(new Exception())).isNull();
}
@Test
void analyzeWhenNoSuchBeanDefinitionExceptionForDifferentTypeShouldReturnNull() {
assertThat(
new NoSuchMailSenderBeanFailureAnalyzer(null).analyze(new NoSuchBeanDefinitionException(String.class)))
.isNull();
}
@Test
void analyzeWhenMailHostPropertyIsConfiguredShouldReturnNull() {
Environment environment = new MockEnvironment().withProperty("spring.mail.host", "smtp.example.org");
assertThat(new NoSuchMailSenderBeanFailureAnalyzer(environment)
.analyze(new NoSuchBeanDefinitionException(MailSender.class))).isNull();
}
@Test
void analyzeWhenMailJndiNamePropertyIsConfiguredShouldReturnNull() {
Environment environment = new MockEnvironment().withProperty("spring.mail.jndi-name", "mail/Session");
assertThat(new NoSuchMailSenderBeanFailureAnalyzer(environment)
.analyze(new NoSuchBeanDefinitionException(MailSender.class))).isNull();
}
@Test
void analyzeWhenMailSenderBeanIsMissingAndNoMailPropertiesAreConfiguredShouldProvideGuidance() {
FailureAnalysis analysis = new NoSuchMailSenderBeanFailureAnalyzer(new MockEnvironment())
.analyze(new NoSuchBeanDefinitionException(MailSender.class));
assertThat(analysis).isNotNull();
assertThat(analysis.getDescription())
.contains("A MailSender bean could not be found")
.contains("spring.mail.host")
.contains("spring.mail.jndi-name");
assertThat(analysis.getAction())
.contains("spring.mail.host")
.contains("spring.mail.jndi-name")
.contains("MailSender bean");
}
@Test
void analyzeWhenJavaMailSenderBeanIsMissingAndNoMailPropertiesAreConfiguredShouldProvideGuidance() {
assertThat(new NoSuchMailSenderBeanFailureAnalyzer(new MockEnvironment())
.analyze(new NoSuchBeanDefinitionException(JavaMailSender.class))).isNotNull();
}
}