'Field mailSender .. required a bean of type 'org.springframework.mail.javamail.JavaMailSender' that could not be found

I'm currently trying to build an email registration process with an email confirmation. I use the JavaMailSender for this. Unfortunately, I am currently getting this error so that my application no longer starts.

I'm also very sure that I'm using the right annotations. But maybe I'm wrong, since I'm relatively new to Sprin Boot

Thats my Error Code

Field mailSender in com.....services.EmailService required a bean of type 'org.springframework.mail.javamail.JavaMailSender' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'org.springframework.mail.javamail.JavaMailSender' in your configuration.

EmailService Class

@Service
public class EmailService {

  @Autowired private JavaMailSender mailSender;

  public void sendVerificationEmail(User user, String siteURL)
      throws MessagingException, UnsupportedEncodingException {
....

mailSender.send(message);
  }
}

In hindsight I use the function in my Auth Service class

@Service
public class AuthService {

....
@Autowired private EmailService emailService;

public JwtResponse signUpUser(SignUpRequest signUpRequest, String siteURL)
      throws MessagingException, UnsupportedEncodingException {...
...

emailService.sendVerificationEmail(user, siteURL);
...

Update after User Comment

Createt a EmailConfiguration Class

@Configuration
public class EmailConfiguration {

  @Autowired private JavaMailSender mailSender;

  @Bean
  public static JavaMailSender getJavaMailSender() {
    JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
    mailSender.setHost("smtp.gmail.com");
    mailSender.setPort(587);

    mailSender.setUsername("[email protected]");
    mailSender.setPassword("password");

    Properties props = mailSender.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");

    return mailSender;
  }
}

and added these to the application properties

spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=username
spring.mail.password=password
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

new Error

 Error creating bean with name 'springSecurityFilterChain' defined in class path resource...

WebSecurityConfig class

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired private UserDetailsServiceImpl userDetailsService;

  @Bean
  private static JwtAuthorizationFilter authenticationJwtTokenFilter() {
    return new JwtAuthorizationFilter();
  }

  @Bean
  private static PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder(12);
  }

  @Override
  public void configure(AuthenticationManagerBuilder authenticationManagerBuilder)
      throws Exception {
    authenticationManagerBuilder
        .userDetailsService(userDetailsService)
        .passwordEncoder(WebSecurityConfig.passwordEncoder());
  }

  @Bean
  @Override
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }

  @Bean
  @Override
  protected void configure(HttpSecurity http) throws Exception {

    // Disable CSRF (cross site request forgery)
    http.cors()
        .and()
        .csrf()
        .disable()
        // No session will be created or used by spring security
        .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        .authorizeRequests()
        .antMatchers("/api/v1/auth/**")
        .permitAll()
        .anyRequest()
        .authenticated();

    // Apply JWT
    http.addFilterBefore(
        WebSecurityConfig.authenticationJwtTokenFilter(),
        UsernamePasswordAuthenticationFilter.class);
  }
}


Solution 1:[1]

In your application.yml you can configure it (set some properties) and add spring-boot-starter-mail to your maven dependencies.

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

as the documentation states:

If spring.mail.host and the relevant libraries (as defined by spring-boot-starter-mail) are available, a default JavaMailSender is created if none exists. The sender can be further customized by configuration items from the spring.mail namespace. See MailProperties for more details.

see: https://docs.spring.io/spring-boot/docs/2.0.x/reference/html/boot-features-email.html

You can also set up this by hand in a @Configuration annotated class. see Baeldung's example: https://www.baeldung.com/spring-email

@Bean
public JavaMailSender getJavaMailSender() {
    JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
    mailSender.setHost("smtp.gmail.com");
    mailSender.setPort(587);

    mailSender.setUsername("[email protected]");
    mailSender.setPassword("password");

    Properties props = mailSender.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");

    return mailSender;
}

I would suggest going with the former as you are using spring boot so let it handle it's stuff. Adding the second for completeness

It looks like the dependencies are an issue: When you use spring-boot you have the basic spring setup it provides and a lot of optional modules (starters) that you can pull in. You don't have to use these which is why they aren't switched on by default.

see for instance: https://www.baeldung.com/spring-boot-starters and https://spring.io/guides/gs/securing-web/

I'll list the dependency you can use and what it is rougly for. just know you don't have to use these they are optional but if you are making a web application spring-boot-starter-web is likely useful.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

similarly if you want to create testcases

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

In your case you want to use spring security so:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
</dependency>

The scope: test part is if you use unit tests (see spring-boot-starter-test earlier). If you don't have the tests (yet) then you could leave it off but it doesn't hurt to have it.

Basically if you use spring boot and you want to have a ready made/connected component from org.springframework.xxxx then there is often a spring-boot-starter-xxxx somewhere. google spring boot starter and the name of the package and you'll get a ton of hits. Look for tutorial code/initial project code as those will likely have the dependencies you need.

After some debugging the remaining issue was found to be: Invalid factory method 'configure' on class

@Bean
@Override
protected void configure(HttpSecurity http) throws Exception { 

This error is caused because @Bean suggests it constructs a bean but it didn't have a return argument. (It had void). Configure shouldn't have @Bean. removing it fixed it.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1