본문 바로가기
스프링

인증 이메일 보내기

by 순원이 2024. 1. 24.

인증 이메일을 보낼 이메일(Google, Naver ...)마다 다르겠지만 추가적인 이메일 설정이 필요합니다. 저는 Gmail을 사용했습니다. Gmail 설정은 이 링크를 참고하세요!

 

 

 

파일 구조

 

Gradle

    implementation'org.springframework.boot:spring-boot-starter-mail'

 

Mailconfig

@Configuration
public class MailConfig {

    @Value("${email.id}")
    private String fromId;

    @Value("${email.password}")
    private String password;


    @Bean
    public JavaMailSender getJavaMailSender() {
        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();

        mailSender.setHost("smtp.gmail.com");
        mailSender.setPort(465);
        mailSender.setUsername(fromId);
        mailSender.setPassword(password);

        Properties props = mailSender.getJavaMailProperties();
        props.put("mail.transport.protocol", "smtp");
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.ssl.enable", "true");
        props.put("mail.debug", "true");
        return mailSender;
    }
}
  •  @Value로 설정되어 있는 값은 yml에 설정하시면 됩니다
  • smtp 프로트콜 이용 (465 포트번호) 
  •  JavaMailSender 객체를 생성하여. 이 객체를 사용해서 이메일을 보내는 것입니다.

 

MailController

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/mail")
@PreAuthorize("isAuthenticated()")
public class MailController {


    private final AuthMailService authMailService;

    /**
     * 인증번호 보내기
     */
    @PostMapping
    public ResponseForm<AuthNumberResponse> sendEmail(@Valid @RequestBody SendMailRequest request, @AuthenticationPrincipal AuthorityUserDTO authorityUserDTO) {
        return new ResponseForm<>(authMailService.sendCodeEmail(request.getEmail(), authorityUserDTO.getProviderId()));
    }
}

참고) AuthorityUserDTO는 Security Context Holder에 담겨져 있는 인증객체(API 요청한 유저)입니다

SendMailRequest

@Data
@NoArgsConstructor
public class SendMailRequest {

    @NotBlank
    private String email;   //인증 번호 받을 이메일
}

 

 

AuthMailService

@Service
@RequiredArgsConstructor
public class AuthMailService {

    private static final Long EXPIRATION = 1800000L; //한시간

    private final RandomGenerator randomGenerator;
    private final SendMailService sendMailService;
    private final RedisUtil redisUtil;

    @Transactional
    public AuthNumberResponse sendCodeEmail(String email, String key) {
            int authNumber = randomGenerator.makeRandomNumber();
            String title = "Flint 회원 가입 인증 이메일 입니다."; // 이메일 제목
            String content =
                    "홈페이지를 방문해주셔서 감사합니다." +    //html 형식으로 작성
                            "<br><br>" +
                            "인증 번호는 " + authNumber + "입니다." +
                            "<br>" +
                            "해당 인증번호를 인증번호 확인란에 기입하여 주세요."; //이메일 내용 삽입
            sendMailService.sendEmail(email, title, content);
            redisUtil.saveAuthNumber(key, String.valueOf(authNumber), EXPIRATION);  //인증번호 검증을 위해 레디스에 저장
            return new AuthNumberResponse(authNumber);
    }
}
  • 이메일 보낼 내용은는 String, html, file 형식으로 보낼 수 있습니다.
  • saveAuthNumber(): 인증번호를 Redis에 담는 메소드. Key는 유저 ProviderId입니다.
  • 인증번호를 Redis에 담은 이유: 관계형 데이터베이스에 담는 것보다 인증번호 검증을 더 빠른 속도로 처리할 수 있습니다.

 

RandomGenerator

@Component
public class RandomGenerator {

    private static final Random random = new Random();
    public int makeRandomNumber() {
        // 난수의 범위 111111 ~ 999999 (6자리 난수)
        return  random.nextInt(888888) + 111111;
    }
}

 

SendMailService

@Service
@RequiredArgsConstructor
public class SendMailService {

    private final JavaMailSender mailSender;

    @Value("${email.id}")
    private String fromId;

    @Async("mailExecutor")
    public void sendEmail(String to, String subject, String content) {
        MimeMessagePreparator messagePreparator =
                mimeMessage -> {
                    //true는 멀티파트 메세지를 사용하겠다는 의미
                    final MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
                    helper.setFrom(fromId);
                    helper.setTo(to);
                    helper.setSubject(subject);
                    helper.setText(content, true);
                };
        mailSender.send(messagePreparator);
    }


}
  • @Async: 비동기화 처리를 위한
  • JavaMailSender로 이메일을 보낼 때 시간이 10초 이상 소요됐습니다. 이는 사용자 경험에 불쾌감을 줄 수 있기 때문에 비동기로 처리했습니다.

AsyncConfig

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    @Override
    @Bean(name = "mailExecutor")
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(10);
        executor.setThreadNamePrefix("Async MailExecutor-");
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return AsyncConfigurer.super.getAsyncUncaughtExceptionHandler();
    }
}

 

 

AuthNumberResponse

@Data
@AllArgsConstructor
public class AuthNumberResponse {
    private int authNumber;
}

 

결과