Create spring-boot-mail module

This commit is contained in:
Brian Clozel 2025-03-17 20:13:20 +01:00 committed by Andy Wilkinson
parent dae3244035
commit c65814b930
28 changed files with 87 additions and 41 deletions

View File

@ -51,6 +51,7 @@ include "spring-boot-project:spring-boot-docker-compose"
include "spring-boot-project:spring-boot-docs"
include "spring-boot-project:spring-boot-jackson"
include "spring-boot-project:spring-boot-jetty"
include "spring-boot-project:spring-boot-mail"
include "spring-boot-project:spring-boot-parent"
include "spring-boot-project:spring-boot-reactor-netty"
include "spring-boot-project:spring-boot-test"

View File

@ -20,6 +20,7 @@ dependencies {
optional(project(":spring-boot-project:spring-boot-amqp"))
optional(project(":spring-boot-project:spring-boot-jackson"))
optional(project(":spring-boot-project:spring-boot-jetty"))
optional(project(":spring-boot-project:spring-boot-mail"))
optional(project(":spring-boot-project:spring-boot-reactor-netty"))
optional(project(":spring-boot-project:spring-boot-tomcat"))
optional(project(":spring-boot-project:spring-boot-undertow"))

View File

@ -26,7 +26,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration;
import org.springframework.boot.mail.autoconfigure.MailSenderAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.mail.javamail.JavaMailSenderImpl;

View File

@ -21,7 +21,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
import org.springframework.boot.actuate.mail.MailHealthIndicator;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration;
import org.springframework.boot.mail.autoconfigure.MailSenderAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import static org.assertj.core.api.Assertions.assertThat;

View File

@ -1645,13 +1645,6 @@
"name": "spring.liquibase.ui-service",
"defaultValue": "logger"
},
{
"name": "spring.mail.test-connection",
"description": "Whether to test that the mail server is available on startup.",
"sourceType": "org.springframework.boot.autoconfigure.mail.MailProperties",
"type": "java.lang.Boolean",
"defaultValue": false
},
{
"name": "spring.mustache.prefix",
"defaultValue": "classpath:/templates/"

View File

@ -78,8 +78,6 @@ org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration

View File

@ -2028,6 +2028,7 @@ bom {
"spring-boot-loader",
"spring-boot-loader-classic",
"spring-boot-loader-tools",
"spring-boot-mail",
"spring-boot-properties-migrator",
"spring-boot-reactor-netty",
"spring-boot-starter",

View File

@ -60,6 +60,7 @@ dependencies {
autoConfiguration(project(path: ":spring-boot-project:spring-boot-devtools", configuration: "autoConfigurationMetadata"))
autoConfiguration(project(path: ":spring-boot-project:spring-boot-jackson", configuration: "autoConfigurationMetadata"))
autoConfiguration(project(path: ":spring-boot-project:spring-boot-jetty", configuration: "autoConfigurationMetadata"))
autoConfiguration(project(path: ":spring-boot-project:spring-boot-mail", configuration: "autoConfigurationMetadata"))
autoConfiguration(project(path: ":spring-boot-project:spring-boot-reactor-netty", configuration: "autoConfigurationMetadata"))
autoConfiguration(project(path: ":spring-boot-project:spring-boot-testcontainers", configuration: "autoConfigurationMetadata"))
autoConfiguration(project(path: ":spring-boot-project:spring-boot-tomcat", configuration: "autoConfigurationMetadata"))
@ -75,6 +76,7 @@ dependencies {
configurationProperties(project(path: ":spring-boot-project:spring-boot-docker-compose", configuration: "configurationPropertiesMetadata"))
configurationProperties(project(path: ":spring-boot-project:spring-boot-jackson", configuration: "configurationPropertiesMetadata"))
configurationProperties(project(path: ":spring-boot-project:spring-boot-jetty", configuration: "configurationPropertiesMetadata"))
configurationProperties(project(path: ":spring-boot-project:spring-boot-mail", configuration: "configurationPropertiesMetadata"))
configurationProperties(project(path: ":spring-boot-project:spring-boot-reactor-netty", configuration: "configurationPropertiesMetadata"))
configurationProperties(project(path: ":spring-boot-project:spring-boot-test-autoconfigure", configuration: "configurationPropertiesMetadata"))
configurationProperties(project(path: ":spring-boot-project:spring-boot-testcontainers", configuration: "configurationPropertiesMetadata"))

View File

@ -7,7 +7,7 @@ TIP: See the {url-spring-framework-docs}/integration/email.html[reference docume
If `spring.mail.host` and the relevant libraries (as defined by `spring-boot-starter-mail`) are available, a default javadoc:org.springframework.mail.javamail.JavaMailSender[] is created if none exists.
The sender can be further customized by configuration items from the `spring.mail` namespace.
See javadoc:org.springframework.boot.autoconfigure.mail.MailProperties[] for more details.
See javadoc:org.springframework.boot.mail.autoconfigure.MailProperties[] for more details.
In particular, certain default timeout values are infinite, and you may want to change that to avoid having a thread blocked by an unresponsive mail server, as shown in the following example:

View File

@ -0,0 +1,37 @@
plugins {
id "java-library"
id "org.springframework.boot.auto-configuration"
id "org.springframework.boot.configuration-properties"
id "org.springframework.boot.docker-test"
id "org.springframework.boot.deployed"
id "org.springframework.boot.optional-dependencies"
}
description = "Spring Boot Mail"
dependencies {
api(project(":spring-boot-project:spring-boot"))
api("org.springframework:spring-context-support")
api("org.eclipse.angus:jakarta.mail")
optional(project(":spring-boot-project:spring-boot-autoconfigure"))
dockerTestImplementation(project(":spring-boot-project:spring-boot-test"))
dockerTestImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support-docker"))
dockerTestImplementation("org.assertj:assertj-core")
dockerTestImplementation("org.awaitility:awaitility")
dockerTestImplementation("org.junit.jupiter:junit-jupiter")
dockerTestImplementation("org.testcontainers:junit-jupiter")
dockerTestImplementation("org.testcontainers:testcontainers")
testImplementation(project(":spring-boot-project:spring-boot-test"))
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-autoconfigure")))
testImplementation("org.assertj:assertj-core")
testImplementation("org.awaitility:awaitility")
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("org.mockito:mockito-core")
testImplementation("org.mockito:mockito-junit-jupiter")
testRuntimeOnly("ch.qos.logback:logback-classic")
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 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.
@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.mail;
package org.springframework.boot.mail.autoconfigure;
import java.net.SocketTimeoutException;
import java.security.cert.CertPathBuilderException;
@ -95,9 +95,9 @@ class MailSenderAutoConfigurationIntegrationTests {
private static final MailpitContainer mailpit = TestImage.container(MailpitContainer.class)
.withSmtpRequireTls(true)
.withSmtpTlsCert(MountableFile
.forClasspathResource("/org/springframework/boot/autoconfigure/mail/ssl/test-server.crt"))
.forClasspathResource("/org/springframework/boot/mail/autoconfigure/ssl/test-server.crt"))
.withSmtpTlsKey(MountableFile
.forClasspathResource("/org/springframework/boot/autoconfigure/mail/ssl/test-server.key"))
.forClasspathResource("/org/springframework/boot/mail/autoconfigure/ssl/test-server.key"))
.withPop3Auth("user:pass");
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
@ -108,9 +108,9 @@ class MailSenderAutoConfigurationIntegrationTests {
this.contextRunner.withPropertyValues("spring.mail.host:" + mailpit.getHost(),
"spring.mail.port:" + mailpit.getSmtpPort(), "spring.mail.ssl.enabled:true",
"spring.mail.ssl.bundle:test-bundle",
"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-ca.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.key",
"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-ca.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.key",
"spring.mail.properties.mail.pop3.host:" + mailpit.getHost(),
"spring.mail.properties.mail.pop3.port:" + mailpit.getPop3Port())
.run((context) -> {
@ -137,9 +137,9 @@ class MailSenderAutoConfigurationIntegrationTests {
this.contextRunner.withPropertyValues("spring.mail.host:" + mailpit.getHost(),
"spring.mail.port:" + mailpit.getSmtpPort(), "spring.mail.properties.mail.smtp.timeout:1000",
"spring.mail.ssl.bundle:test-bundle",
"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-ca.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.key")
"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-ca.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.key")
.run((context) -> {
JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);
assertThatException().isThrownBy(() -> mailSender.send(createMessage("Should fail")))
@ -156,9 +156,9 @@ class MailSenderAutoConfigurationIntegrationTests {
private static final MailpitContainer mailpit = TestImage.container(MailpitContainer.class)
.withSmtpRequireStarttls(true)
.withSmtpTlsCert(MountableFile
.forClasspathResource("/org/springframework/boot/autoconfigure/mail/ssl/test-server.crt"))
.forClasspathResource("/org/springframework/boot/mail/autoconfigure/ssl/test-server.crt"))
.withSmtpTlsKey(MountableFile
.forClasspathResource("/org/springframework/boot/autoconfigure/mail/ssl/test-server.key"))
.forClasspathResource("/org/springframework/boot/mail/autoconfigure/ssl/test-server.key"))
.withPop3Auth("user:pass");
final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
@ -170,9 +170,9 @@ class MailSenderAutoConfigurationIntegrationTests {
"spring.mail.port:" + mailpit.getSmtpPort(),
"spring.mail.properties.mail.smtp.starttls.enable:true",
"spring.mail.properties.mail.smtp.starttls.required:true", "spring.mail.ssl.bundle:test-bundle",
"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-ca.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.key",
"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-ca.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.key",
"spring.mail.properties.mail.pop3.host:" + mailpit.getHost(),
"spring.mail.properties.mail.pop3.port:" + mailpit.getPop3Port())
.run((context) -> {
@ -188,9 +188,9 @@ class MailSenderAutoConfigurationIntegrationTests {
"spring.mail.port:" + mailpit.getSmtpPort(), "spring.mail.ssl.enabled:true",
"spring.mail.properties.mail.smtp.starttls.enable:true",
"spring.mail.properties.mail.smtp.starttls.required:true", "spring.mail.ssl.bundle:test-bundle",
"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-ca.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.key",
"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-ca.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.crt",
"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.key",
"spring.mail.properties.mail.pop3.host:" + mailpit.getHost(),
"spring.mail.properties.mail.pop3.port:" + mailpit.getPop3Port())
.run((context) -> {

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.mail;
package org.springframework.boot.mail.autoconfigure;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.mail;
package org.springframework.boot.mail.autoconfigure;
import jakarta.activation.MimeType;
import jakarta.mail.internet.MimeMessage;
@ -25,8 +25,8 @@ import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration.MailSenderCondition;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.mail.autoconfigure.MailSenderAutoConfiguration.MailSenderCondition;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Import;
import org.springframework.mail.MailSender;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.mail;
package org.springframework.boot.mail.autoconfigure;
import javax.naming.NamingException;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.mail;
package org.springframework.boot.mail.autoconfigure;
import java.util.Map;
import java.util.Properties;
@ -22,7 +22,7 @@ import java.util.Properties;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.mail.MailProperties.Ssl;
import org.springframework.boot.mail.autoconfigure.MailProperties.Ssl;
import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.context.annotation.Bean;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.mail;
package org.springframework.boot.mail.autoconfigure;
import jakarta.mail.MessagingException;

View File

@ -17,4 +17,4 @@
/**
* Auto-configuration for email support.
*/
package org.springframework.boot.autoconfigure.mail;
package org.springframework.boot.mail.autoconfigure;

View File

@ -0,0 +1,12 @@
{
"groups": [],
"properties": [
{
"name": "spring.mail.test-connection",
"description": "Whether to test that the mail server is available on startup.",
"sourceType": "org.springframework.boot.autoconfigure.mail.MailProperties",
"type": "java.lang.Boolean",
"defaultValue": false
}
]
}

View File

@ -0,0 +1,2 @@
org.springframework.boot.mail.autoconfigure.MailSenderAutoConfiguration
org.springframework.boot.mail.autoconfigure.MailSenderValidatorAutoConfiguration

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.mail;
package org.springframework.boot.mail.autoconfigure;
import java.util.Properties;

View File

@ -6,6 +6,5 @@ description = "Starter for using Java Mail and Spring Framework's email sending
dependencies {
api(project(":spring-boot-project:spring-boot-starters:spring-boot-starter"))
api("org.springframework:spring-context-support")
api("org.eclipse.angus:jakarta.mail")
api(project(":spring-boot-project:spring-boot-mail"))
}