Add configurable SMTP timeouts (#43594)

* Add configurable SMTP timeouts

closes #35836 #14509

Signed-off-by: Christian Janker <christian.janker@gmx.at>

* Allow setting SMTP timeout in realm settings

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>

---------

Signed-off-by: Christian Janker <christian.janker@gmx.at>
Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
Co-authored-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
Christian Ja
2025-12-11 12:19:09 +01:00
committed by GitHub
parent c0c4067bdd
commit 4e01d85772
4 changed files with 88 additions and 4 deletions

View File

@@ -3666,3 +3666,9 @@ claimDisplayLocalePlaceholder=e.g., en, de, fr
addClaimDisplay=Add display entry
removeClaimDisplay=Remove display entry
noClaimDisplayEntries=No display entries. Display entries provide user-friendly claim names for different locales in wallet applications.
smtpConnectionTimeout=Connection timeout
smtpConnectionTimeoutHelp=The timeout in milliseconds for connecting to the SMTP server.
smtpSocketReadTimeout=Socket read timeout
smtpSocketReadTimeoutHelp=The timeout in milliseconds for reading from the SMTP server.
smtpSocketWriteTimeout=Socket write timeout
smtpSocketWriteTimeoutHelp=The timeout in milliseconds for writing to the SMTP server.

View File

@@ -312,6 +312,30 @@ export const RealmSettingsEmailTab = ({
labelOff={t("disabled")}
stringify
/>
<TextControl
name="smtpServer.connectionTimeout"
label={t("smtpConnectionTimeout")}
labelIcon={t("smtpConnectionTimeoutHelp")}
type="number"
defaultValue={10000}
min={0}
/>
<TextControl
name="smtpServer.timeout"
label={t("smtpSocketReadTimeout")}
labelIcon={t("smtpSocketReadTimeoutHelp")}
type="number"
defaultValue={10000}
min={0}
/>
<TextControl
name="smtpServer.writeTimeout"
label={t("smtpSocketWriteTimeout")}
labelIcon={t("smtpSocketWriteTimeoutHelp")}
type="number"
defaultValue={10000}
min={0}
/>
<Controller
name="smtpServer.debug"
control={control}

View File

@@ -105,7 +105,7 @@ public class DefaultEmailSenderProvider implements EmailSenderProvider {
checkFromAddress(config.get("from"), isAllowUTF8(config));
}
private Properties buildEmailProperties(Map<String, String> config, String from) throws EmailException {
Properties buildEmailProperties(Map<String, String> config, String from) throws EmailException {
Properties props = new Properties();
if (config.containsKey("host")) {
@@ -142,9 +142,9 @@ public class DefaultEmailSenderProvider implements EmailSenderProvider {
setupTruststore(props);
}
props.setProperty("mail.smtp.timeout", "10000");
props.setProperty("mail.smtp.connectiontimeout", "10000");
props.setProperty("mail.smtp.writetimeout", "10000");
props.setProperty("mail.smtp.timeout", config.getOrDefault("timeout", "10000"));
props.setProperty("mail.smtp.connectiontimeout", config.getOrDefault("connectionTimeout", "10000"));
props.setProperty("mail.smtp.writetimeout", config.getOrDefault("writeTimeout", "10000"));
String envelopeFrom = config.get("envelopeFrom");
if (isNotBlank(envelopeFrom)) {

View File

@@ -0,0 +1,54 @@
package org.keycloak.email;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
class DefaultEmailSenderProviderTest {
@Test
void testEmailTimeoutPropertiesDefaults() throws EmailException {
// given
DefaultEmailSenderProvider defaultEmailSenderProvider = new DefaultEmailSenderProvider(
null, null
);
String from = "test@keycloak.com";
Map<String, String> config = new HashMap<>();
// when
Properties properties = defaultEmailSenderProvider.buildEmailProperties(config, from);
// then
assertThat(properties.getProperty("mail.smtp.timeout"), is("10000"));
assertThat(properties.getProperty("mail.smtp.connectiontimeout"), is("10000"));
assertThat(properties.getProperty("mail.smtp.writetimeout"), is("10000"));
}
@Test
void testEmailTimeoutPropertiesFromConfig() throws EmailException {
// given
DefaultEmailSenderProvider defaultEmailSenderProvider = new DefaultEmailSenderProvider(
null, null
);
String from = "test@keycloak.com";
Map<String, String> config = new HashMap<>();
config.put("timeout", "20000");
config.put("connectionTimeout", "30000");
config.put("writeTimeout", "40000");
// when
Properties properties = defaultEmailSenderProvider.buildEmailProperties(config, from);
// then
assertThat(properties.getProperty("mail.smtp.timeout"), is("20000"));
assertThat(properties.getProperty("mail.smtp.connectiontimeout"), is("30000"));
assertThat(properties.getProperty("mail.smtp.writetimeout"), is("40000"));
}
}