복잡한뇌구조마냥

[Spring] SMTP 기반 메일 인증 ( + 비동기 처리 ) 본문

BE/Spring

[Spring] SMTP 기반 메일 인증 ( + 비동기 처리 )

지금해냥 2025. 11. 30. 14:33

1. SMTP란 무엇인가?

SMTP(Simple Mail Transfer Protocol)는
애플리케이션 → 메일 서버 → 사용자의 메일함
으로 메일을 전달하는 메일 전송 프로토콜이다.

Spring Boot에서는 내부적으로 SMTP 서버(Gmail, Naver, Outlook, 회사 SMTP 등)에 접속해서
로그인 → 메일 전송 → 서버가 사용자에게 전달
이라는 과정을 수행한다.

우리가 할 일은 단순히 SMTP 서버 설정 + JavaMailSender 호출뿐이다.


2. Spring Boot SMTP 설정 (application.yml)

프로젝트에서는 보안상 메일 정보를 환경변수로 분리해두고 아래와 같이 설정했다.

 
spring:
  mail:
    host: ${SPRING__MAIL__HOST}
    port: ${SPRING__MAIL__PORT}
    username: ${SPRING__MAIL__USERNAME}
    password: ${SPRING__MAIL__PASSWORD}
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: true

✔ 주요 설정 요약

항목 설명
host SMTP 서버 주소 (smtp.gmail.com, smtp.naver.com 등)
port 587(STARTTLS), 465(SSL)
auth: true SMTP 로그인 필요 설정
starttls.enable: true TLS 기반 암호화로 안전하게 전송
starttls.required: true TLS 사용이 필수

환경변수로 분리한 이유는 다음 두 가지다:

  1. 깃허브에 메일 계정 비밀번호 노출 방지
  2. 로컬/배포 환경마다 다른 계정을 유연하게 사용할 수 있음

의존성 추가

implementation("org.springframework.boot:spring-boot-starter-mail")

3. JavaMailSender로 이메일 발송하기

Spring Boot는 JavaMailSender Bean을 자동으로 생성해주기 때문에 바로 주입해서 사용할 수 있다.

📌 이메일 발송 서비스

 
@Service
@RequiredArgsConstructor
public class EmailSender {

    private final JavaMailSender mailSender;

    @Async("emailExecutor")
    public void sendMailAsync(String email, String code) {
        String subject = "[Chwi-Meet] 이메일 인증코드 안내";
        String content = """
                안녕하세요.

                이메일 인증을 위해 아래 인증코드를 입력해주세요.

                인증코드: %s

                유효시간: 5분

                감사합니다.
                """.formatted(code);

        SimpleMailMessage message = new SimpleMailMessage();
        message.setTo(email);
        message.setSubject(subject);
        message.setText(content);

        mailSender.send(message);
    }
}

SimpleMailMessage를 사용하는 이유

  • 제목, 본문, 수신자만 필요할 때 사용
  • HTML 메일이나 첨부파일이 필요하면 MimeMessageHelper 사용

4. 비동기 처리(@Async) 적용 이유

메일 전송은 외부 SMTP 서버와의 통신이 포함되어 있어서 지연 시간이 발생할 수 있다.

그 지연을 모두 API 응답 시간으로 포함시키면 다음과 같은 문제가 생긴다:

  • 회원가입 API 응답이 느려짐
  • 인증 요청을 여러 번 호출하면 서버 쓰레드 점유됨
  • 사용자가 UI에서 “버튼이 안 눌림” 같은 문제를 경험

그래서 메일 전송은 메인 스레드가 아닌 별도 스레드에서 처리하도록 @Async를 붙였다.

  • 동기

  • 비동기

📌 비동기 전용 쓰레드풀 설정

 
@Configuration
@EnableAsync
public class AsyncConfig {

    @Bean(name = "emailExecutor")
    public Executor emailExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("email-");
        executor.initialize();
        return executor;
    }
}

결과

  • API는 즉시 응답하고
  • 메일은 백그라운드에서 안전하게 발송됨
  • SMTP 서버 지연이 있어도 사용자 경험에 영향 없음

5. 이메일 인증 Flow 정리

정확한 인증 흐름을 기록해두면 다음에 재사용하기 편하다.

  1. 사용자가 이메일 인증 요청
  2. 서버에서 인증코드 생성 (ex. 6자리 숫자)
  3. Redis에 5분 TTL로 저장
  4. EmailSender.sendMailAsync() 호출
  5. 사용자에게 메일 도착
  6. 입력된 인증코드와 Redis 저장값 비교
  7. 성공 → 인증 완료 처리

구조가 간단해보여도 실제 서비스에서는
보안/속도/안정성을 모두 고려해야 하기 때문에
SMTP 설정 + 비동기 처리는 꼭 필요한 구성이다.


마무리

정리하자면 Spring Boot에서 이메일 인증 기능은 다음 두 가지면 완성된다.

  1. SMTP 설정 → application.yml
  2. JavaMailSender로 발송 + @Async 처리

이번 프로젝트에서 메일 인증 속도는
기본 2~3초에서 100ms 이하로 개선되었고,
API 응답 성능에도 영향을 주지 않는 구조로 마무리할 수 있었다.

LIST