首页 > 解决方案 > 如何让 JavaMailSender 在错误的邮件密码上加载应用程序上下文时不会失败?

问题描述

我在 Sring Boot 应用程序中使用 JavaMailSender,如果像密码这样的属性是错误的,以防止登录邮件网关,那么它无法自动装配 bean,并且应用程序上下文无法加载。

Spring邮件属性:

spring.mail.host=smtp.gmail.com
spring.mail.port=465
spring.mail.protocol=smtp
spring.mail.username=xxx@gmail.com
spring.mail.password=xxx
spring.mail.from=xxx@gmail.com

属性由属性读取器加载:

public abstract class AbstractUserProperties implements ApplicationProperties {

    @Value("${" + PropertyNames.CONFIG_AUTH_TOKEN_PRIVATE_KEY + "}")
    private String authenticationTokenPrivateKey;

    @Value("${" + PropertyNames.CONFIG_MAIL_HOST + "}")
    private String host;

    @Value("${" + PropertyNames.CONFIG_MAIL_PORT + "}")
    private String port;

    @Value("${" + PropertyNames.CONFIG_MAIL_PROTOCOL + "}")
    private String protocol;

    @Value("${" + PropertyNames.CONFIG_MAIL_USERNAME + "}")
    private String username;

    @Value("${" + PropertyNames.CONFIG_MAIL_PASSWORD + "}")
    private String password;

    @Value("${" + PropertyNames.CONFIG_MAIL_FROM + "}")
    private String mailFrom;

    @Value("${" + PropertyNames.CONFIG_MAIL_TEST_CONNECTION + "}")
    private boolean mailTestConnection;

    @Value("${" + PropertyNames.CONFIG_MAILING_ENABLED + "}")
    private boolean mailingEnabled;

    public String getAuthenticationTokenPrivateKey() {
        return authenticationTokenPrivateKey;
    }

    @Override
    public String getHost() {
        return host;
    }

    @Override
    public String getPort() {
        return port;
    }

    @Override
    public String getProtocol() {
        return protocol;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getMailFrom() {
        return mailFrom;
    }

    @Override
    public boolean getMailTestConnection() {
        return mailTestConnection;
    }

    @Override
    public boolean getMailingEnabled() {
        return mailingEnabled;
    }

}

如何让错误的邮件密码不会阻止应用程序启动?

依赖项:

<version>2.0.3.RELEASE</version>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

我在Spring Boot 2.0.3

这是应用程序的邮件配置:

@Configuration
public class MailConfig {

    @Autowired
    private ApplicationProperties applicationProperties;

    @Bean
    public JavaMailSender javaMailSender() {
        String host = applicationProperties.getHost();
        String port = applicationProperties.getPort();
        String protocol = applicationProperties.getProtocol();
        String username = applicationProperties.getUsername();
        String password = applicationProperties.getPassword();
        if (!password.isEmpty() && !username.isEmpty() && !protocol.isEmpty() && !port.isEmpty() && !host.isEmpty()) {
            JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
            javaMailSender.setHost(host);
            javaMailSender.setPort(Integer.parseInt(port));
            javaMailSender.setProtocol(protocol);
            javaMailSender.setUsername(username);
            javaMailSender.setPassword(password);
            javaMailSender.setJavaMailProperties(getMailProperties());
            return javaMailSender;
        } else {
            return null;
        }
    }

    @Bean
    public SimpleMailMessage simpleMailMessage() {
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setFrom(applicationProperties.getMailFrom());
        return simpleMailMessage;
    }

    private Properties getMailProperties() {
        Properties properties = new Properties();
        properties.setProperty("mail.smtp.auth", "true");
        properties.setProperty("mail.smtp.starttls.enable", "false");
        properties.setProperty("mail.smtp.quitwait", "false");
        properties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        properties.setProperty("mail.smtp.socketFactory.fallback", "false");
        properties.setProperty("mail.debug", "true");
        return properties;
    }

}

更新:我已将spring.mail.test-connection=false属性放在application.properties文件中,控制台日志显示它已被复制:

[INFO] Copying 1 resource
[DEBUG] Copying file application.properties

我还删除了MailConfig该类,以便默认使用 Spring 提供的类。错误消息仍然相同。作为旁注,我想知道如何在我自己的 bean 配置中使用该属性,而不必使用默认的 Spring bean。

更新:我可以mail.test-connection在我的配置 bean 中添加属性,如下所示:

private Properties getMailProperties() {
    Properties properties = new Properties();
    properties.setProperty("mail.smtp.auth", "true");
    properties.setProperty("mail.smtp.starttls.enable", "false");
    properties.setProperty("mail.smtp.quitwait", "false");
    properties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
    properties.setProperty("mail.smtp.socketFactory.fallback", "false");
    properties.setProperty("mail.debug", "true");
    properties.setProperty("mail.test-connection", String.valueOf(applicationProperties.getMailTestConnection()));
    return properties;
}

@Bean
public JavaMailSender javaMailSender() {
    String host = applicationProperties.getHost();
    String port = applicationProperties.getPort();
    String protocol = applicationProperties.getProtocol();
    String username = applicationProperties.getUsername();
    String password = applicationProperties.getPassword();
    JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
    javaMailSender.setHost(host);
    javaMailSender.setPort(Integer.parseInt(port));
    javaMailSender.setProtocol(protocol);
    javaMailSender.setUsername(username);
    javaMailSender.setPassword(password);
    javaMailSender.setJavaMailProperties(getMailProperties());
    return javaMailSender;
}

现在,即使没有提供密码,也没有检查连接,应用程序上下文也可以正常加载。

标签: spring-bootjakarta-mail

解决方案


您可以将以下行添加到application.properties文件中,以便在应用程序启动时不对邮件连接进行测试:

spring.mail.test-connection=false

使用此配置,如果您第一次尝试发送邮件,将检查您的邮件连接,如果您的密码不正确,则会引发异常。

但我不确定你为什么要这样做:D

更新:如果您想知道 Spring Boot 是如何做到的,请查看它们使用以下代码测试连接的XYZAutoConfiguration类:MailSender

/**
 * {@link EnableAutoConfiguration Auto configuration} for testing mail service
 * connectivity on startup.
 *
 * @author Eddú Meléndez
 * @author Stephane Nicoll
 * @since 1.3.0
 */
@Configuration
@AutoConfigureAfter(MailSenderAutoConfiguration.class)
@ConditionalOnProperty(prefix = "spring.mail", value = "test-connection")
@ConditionalOnSingleCandidate(JavaMailSenderImpl.class)
public class MailSenderValidatorAutoConfiguration {

    private final JavaMailSenderImpl mailSender;

    public MailSenderValidatorAutoConfiguration(JavaMailSenderImpl mailSender) {
        this.mailSender = mailSender;
    }

    @PostConstruct
    public void validateConnection() {
        try {
            this.mailSender.testConnection();
        }
        catch (MessagingException ex) {
            throw new IllegalStateException("Mail server is not available", ex);
        }
    }

}

推荐阅读