7

I am trying to use JavaMailSender to send mails in spring boot, but I am getting this error:

javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate). Failed messages: javax.mail.MessagingException: Could not convert socket to TLS;
  nested exception is:
    javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)

After doing some reading, I found it is because we are using TLSv1 or TLSv1.1 which is outdated, and we should use v1.2 or higher. I tried to add ssl.protocols property in application.yml with value TLSv1.2, but it does not seem to work. Here is my application.yml:

spring:
  mail:
    host: smtp.gmail.com
    port: 587
    username: ******@gmail.com
    password: *******
    protocol: smtp
    tls: true
    properties.mail.smtp:
      auth: true
      ssl.trust: smtp.gmail.com
      starttls.required: true
      starttls.enabled: true
      ssl.protocols: TLSv1.2

and here is the method that sends the mail:

public void sendEmail(String to, String subject, String body) {
    logger.info("Sending mail to : " + to);
    SimpleMailMessage mail = new SimpleMailMessage();
    mail.setTo(to);
    mail.setSubject(subject);
    mail.setText(body);

    try {
        javaMailSender.send(mail);
        logger.info("Mail sent to " + to);
    } catch (Exception e) {
        logger.error("Could not send mail to " + to + ". Exception : " + e.getMessage());
    }
}

I updated JavaMailSender version but it didn't fix the issue. The only thing that worked was removing TLSv1 and TLSv1.1 from jdk.tls.disabledAlgorithms as suggested in this answer, but it is only a temporary fix. How can make the mail sender use TLSv1.2 or higher? Is there anything wrong in the way I am defining the ssl.protocols property in application.yml?

This is the java version I am using:

openjdk version "1.8.0_292"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_292-b10)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.292-b10, mixed mode)

and the spring boot starter mail version:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
    <version>2.5.3</version>
</dependency>
VishnuVS
  • 1,055
  • 2
  • 14
  • 29
  • Is it starttls.enables: true or starttls.enable: true With s removed from enables – Sagii Aug 23 '21 at 07:42
  • You may add ssl.protocols : TLSv1.2 property Or ssl.enable : false – Sagii Aug 23 '21 at 07:49
  • I'm not convinced the TLS version is the problem. Consider 'or cipher suites are inappropriate'. Does the mail server have a certificate and private key? and what cipher suites does it support. – user207421 Aug 23 '21 at 08:07
  • @Sagii it was starttls.enables in my properties file, thanks for pointing it out. I corrected it, and also tried providing ssl.enable:false instead of ssl.protocols:TLSv1.2, but still same error. – VishnuVS Aug 23 '21 at 09:53
  • @user207421 I am using gmail for sending the mail. I checked the supported ciphers now and found this https://support.google.com/a/answer/9795993?hl=en – VishnuVS Aug 23 '21 at 09:56

4 Answers4

13

I recently answered an almost identical question.

As you guessed, your problem will be related with a change introduced in the JDK in order to disable by default insecure TLS protocol versions:

security-libs/javax.net.ssl
Disable TLS 1.0 and 1.1

TLS 1.0 and 1.1 are versions of the TLS protocol that are no longer considered secure and have been superseded by more secure and modern versions (TLS 1.2 and 1.3).

These versions have now been disabled by default. If you encounter issues, you can, at your own risk, re-enable the versions by removing "TLSv1" and/or "TLSv1.1" from the jdk.tls.disabledAlgorithms security property in the java.security configuration file.

As you can see in the bug description, the change has been backported to different JDK versions, the one you are using among them.

In order to solve the problem you can edit your java.security configuration file and remove TLSv1 and/or TLSv1.1 from the jdk.tls.disabledAlgorithms security property.

In addition, you can explicitly include the required TLS protocol in your configuration properties:

props.put("mail.smtp.ssl.protocols", "TLSv1.2");

I honestly do not understand why Spring Boot is not applying this configuration, it seems you defined it right. You can check it reviewing the source code of the library when describing mail properties configuration and the different accepted mail properties, and as described in the Spring Boot documentation as well. Please, try defining the property like this:

spring:
  mail:
    properties:
      # other properties you need
      "mail.smtp.ssl.protocols": "TLSv1.2"

In order to discard some problem maybe related to YAML formatting, you can try set this property explicitly, just for testing, in JavaMaiSenderImpl:

public void sendEmail(String to, String subject, String body) {
    logger.info("Sending mail to : " + to);
    SimpleMailMessage mail = new SimpleMailMessage();
    mail.setTo(to);
    mail.setSubject(subject);
    mail.setText(body);

    try {
        // Just for validating the solution
        JavaMailSenderImpl javaMailSenderImpl = (JavaMailSenderImpl)javaMailSender;
        // Please, put a breakpoint here and debug the configured
        // properties, it will provide you a valuable information
        // about the actual properties that have been applied      
javaMailSenderImpl.getJavaMailProperties().put("mail.smtp.ssl.protocols", "TLSv1.2");

        javaMailSender.send(mail);
        logger.info("Mail sent to " + to);
    } catch (Exception e) {
        logger.error("Could not send mail to " + to + ". Exception : " + e.getMessage());
    }
}
jccampanero
  • 50,989
  • 3
  • 20
  • 49
  • sorry for being so late to respond. We were updating our java version and somehow our integration tests all got messed up, so I couldn't verify this. I thought of replying after we fix the tests, but I don't think it will be fixed soon. Luckily, I am not getting this error in Java 11. I will be awarding you the bounty anyways @jccampanero – VishnuVS Aug 27 '21 at 17:25
  • 1
    Hi @VishnuVS.Please, there is no need to apologize. Thank you very much for awarding me the bounty. Please, in any case, I hope that you actually solve the problem: do not hesitate to contact me back when you fix the tests, I will be glad to help if I can. In addition, please, be aware that the change is back ported to several JDK versions, probably to the one you will use with Java 11 too. As I told you, please, contact me again if you think that I can be helpful. – jccampanero Aug 27 '21 at 17:33
  • Fantastic! This problem has been plaguing us for months on one server with a very recent version of open-jdk, but not on another with a very slightly older version. Simply adding : props.put("mail.smtp.ssl.protocols", "TLSv1.2"); fixed it everywhere. Thank you! – balm Dec 08 '21 at 23:00
  • That is great @balm. I am happy to hear that the answer was helpful and you were able to solve your problem. – jccampanero Dec 08 '21 at 23:05
0
You can add this property to your configurations:
            Properties props = javaMailSender.getJavaMailProperties();
            props.put("mail.transport.protocol", "smtp");
            props.put("mail.smtp.auth", "true");
            props.put("mail.smtp.starttls.enable", "true");
            props.put("mail.debug", "true");
            props.put("mail.smtp.ssl.trust", "*");
            props.put("mail.smtp.ssl.protocols", "TLSv1.2");
        
Sri
  • 1
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Diego Borba Aug 31 '23 at 03:44
-1

You can do it by setting System.setProperty("mail.smtp.ssl.protocols", protocols);. For example:

String protocols = String.join(" ", 
    SSLContext
        .getDefault()
        .getSupportedSSLParameters()
        .getProtocols()
);

System.setProperty("mail.smtp.ssl.protocols", protocols);

In any case, this config it's working without any configuration

  mail:
    host: smtp.gmail.com
    port: 587
    username: ***@gmail.com
    password: P4ssw0rd
    properties:
      mail:
        smtp:
          starttls:
            enable: true
            required: true
      auth: true
Jose A. Matarán
  • 1,044
  • 3
  • 13
  • 33
  • It's hard to see how setting `mail.smtp.ssl.protocols` to the supported protocols would do anything except assert the existing defaults. If anything it would make it worse, by adding all the supported but disabled protocols such as the anonymous ones. – user207421 Aug 23 '21 at 08:08
-2

I have a similar problem when I use application.properties the error I was getting is:

-dev.miku.r2dbc.mysql.client.MySqlConnectionClosedException: Connection unexpectedly closed -d.m.r.mysql.client.ReactorNettyClient : Error: No appropriate protocol (protocol is disabled or cipher suites are inappropriate) -12-16 14:48:30.287 WARN 27232 --- [actor-tcp-nio-2] d.m.r.mysql.client.ReactorNettyClient : Connection has been closed by peer 2021-12-16 14:48:30.288 ERROR 27232 --- [actor-tcp-nio-2] reactor.core.publisher.Operators : Operator called default onErrorDropped

HERE IS MY SOLUTION:

Just one line solved the issue:

spring.r2dbc.properties.ssl= false
cigien
  • 57,834
  • 11
  • 73
  • 112
  • Where are you adding your "one line" to solve the issue? Also, if I am not mistaken, this appears to be turning off ssl. – matt Dec 16 '21 at 15:16