Spring Boot 이메일 발송(Google SMTP)

Chooooo·2023년 12월 27일
0

인턴생활

목록 보기
19/19

😎 프로젝트에 필요한 기능

현재 인턴으로서, 12월 말까지 현재 회사에서 근무하고 바로 싸피를 1월 2일부터 진행해야 한다.. 하지만 마지막까지 할 일은 해야하기에 구현한 기능을 써보려고 한다.

현재 프로젝트에서 필요한 것은 이메일 알림 발송 API

  • 광고주에게 광고비 충전 알림을 보내는 기준 금액을 설정
  • 광고주의 충전 금액이 해당 금액 이하가 됐을 때 이메일 알림을 발송
  • 알림 발송은 24시간마다 한 번씩 최대 3회까지 발송
  • 3회 모두 발송되기 전에 광고주가 충전을 해서 기준 금액 초과가 되면 발송 중단

위 기능을 구현해야 한다. 스케줄링에 앞서 먼저 이메일 알림 발송 기능을 구현하고자 한다.

알림 API 구축

DB에서 광고주의 충전 금액을 확인하고, 특정 조건에 따라 이메일을 발송하는 로직이 포함되어야 한다. 이 과정에서 백엔드 단에서 스케줄러를 사용하여 정기적으로 실행되는 작업을 수행할 예정.

데이터베이스 설계: 광고주의 충전 금액, 알림 발송 횟수 및 마지막 알림 발송 시간을 저장할 수 있는 테이블이 필요

API 엔드포인트 구현: 광고주가 충전 금액을 설정하거나 업데이트할 수 있는 API를 구현

스케줄링 로직 구현: 24시간마다 실행되는 스케줄러를 구축하여 광고주의 충전 금액이 설정된 기준 이하로 떨어졌는지 확인

알림 발송 로직 구현: 충전 금액이 기준 이하로 떨어진 광고주에게 이메일 알림을 발송. 이미 3회 발송된 광고주는 제외.

충전 금액 업데이트 로직 구현: 광고주가 충전할 때마다 충전 금액을 업데이트하고, 알림 발송 카운트를 초기화

DB 설계

  • current_balance (현재 잔액)
  • notification_threshold (알림 기준 금액)
  • notification_count (발송된 알림 횟수)
  • last_notification_sent (마지막 알림 발송 시간)

😊 Spring Boot 이메일 발송하기

웹 서비스를 기획하고 구성하다보면 이메일 관련한 작업을 해야할 경우가 많이 발생한다는 것을 실무에서 깨달았다...

예를 들면, 우리가 많이 접하는 회원 가입 시 이메일 인증, 각종 알림을 위한 이메일 전송 등이 존재한다.

  • 다양한 라이브러리가 이미 존재하기 때문에 선택을 해야한다.
  • 이메일을 발송하는 가장 일반적인 방법 중 하나는 Java Mail API를 사용하는 것!!

2022.05.30일부터는 Google 약관이 변경되어 2단계 인증(앱 비밀번호 사용)을 해야 사용가능

🐳 Step1 Gmail SMTP 서버 설정

# SMTP
# Email
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=~~~@gmail.com
spring.mail.password=~~~


# Email - Option
spring.mail.properties.mail.debug=true
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.starttls.enabled=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.auth=false

설정 설명 순서대로..

  • SMTP 서버 호스트 : smtp.gmail.com
  • SMTP 서버 포트 : 587 ( Google 경우 587 사용 )
  • SMTP 서버 로그인 아이디 (풀주소 사용 가능 ex example@google.com)
  • SMTP 서버 로그인 패스워드 : 발급받은 앱 비밀번호
  • SMTP 서버 Debug : 메일 전송 시 상황, 로그를 확인하는 것
  • TimeOut 제한
  • starttls 설정 = true --> SSL/TLS 기반의 SMTPS 기능, 즉 보안 기능 활성화
  • 위와 동일

🐳 Mail Service 작성

@Service
@RequiredArgsConstructor
public class EmailService {

    private final JavaMailSender javaMailSender;

    /**
     * @info : 지정된 주소로 이메일 전송
     * @name : sendMail
     * @Descroption : 이메일 주소, 내용, 제목이 필요
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    private static class EmailDto {
        private String title;
        private String from;
        private String to;
        private String text;
    }

    @Async
    public boolean sendMailMime(EmailDto emailDto) throws MessagingException {
        try {
            MimeMessage message = javaMailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, "utf-8");

            helper.setTo(emailDto.getTo());
            helper.setFrom(emailDto.getFrom());
            helper.setSubject(emailDto.getTitle());
            helper.setText(emailDto.getText(), false);

            javaMailSender.send(message);
            return true;  // 이메일 전송 성공
        } catch (MessagingException e) {
            e.printStackTrace();
            return false;   // 이메일 전송 실패
        }

        /**
         * 첨부 파일이나 HTML을 보낼 때는 MimeMessageHelper 활용
         * helper.setText("<h1>Check out this image!</h1><img src='cid:id101'/>", true); // HTML 본문 설정
         * helper.addInline("id101", new ClassPathResource("path/to/image.png")); // 이미지 첨부
         * helper.addAttachment("invoice.pdf", new ClassPathResource("path/to/invoice.pdf")); // PDF 파일 첨부
         */
    }
}

이메일을 보내기 위해 spring.mail 속성을 사용하는 경우 JavaMailSender를 통해 이메일을 보내는 과정에서 자동으로 설정되는 것이 있다.

  • 바로 spring.mail.username, spring.mail.password이다.
  • 해당 값이 자동으로 설정된다 !

그렇기에 EmailDto에서 from 필드를 명시적으로 설정하지 않아도, JavaMailSender는 application.properties 파일의 spring.mail.username값을 기본 발신자 주소로 사용한다.
그러므로 실제 EmailDto에서 to(수신자 주소)와 text(이메일 본문)만 지정해주면 된다 !!

@Async 어노테이션

@Async 어노테이션은 스프링 프레임워크에서 비동기 실행을 지원하기 위한 것.
메소드에 어노테이션을 추가하면 스프링은 해당 메서드를 호출하는 즉시 새로운 스레드에서 실행한다.
-> 이는 호출자가 메소드 실행을 기다리지 않고, 즉시 다음 작업으로 진행할 수 있게 해준다.

비동기 방식 사용 상황

🎈 긴 처리 시간 : 메소드가 오래 걸리는 작업을 수행해야 할 때, 예를 들어, 대량의 데이터 처리나 복잡한 계산 등을 수행해야 하는 경우
🎈 리소스 집약적 작업 : 외부 API 호출이나 디스크 I/O와 같이 리소스를 많이 사용하는 작업을 수행해야 할 때
🎈 사용자 경험 향상 : 클라이언트(예: 웹 브라우저)가 서버의 응답을 기다리지 않고 다른 작업을 계속할 수 있게 함으로써 사용자 경험을 향상시킬 수 있다.

예를 들어, 사용자가 웹 애플리케이션에서 어떤 작업을 요청했을 때, 그 작업이 백그라운드에서 비동기적으로 실행되고, 사용자는 그 작업이 완료될 때까지 다른 페이지를 탐색하거나 다른 작업을 계속할 수 있습니다.

비동기 메소드를 사용하면, 메일을 보내는 작업 같은 경우에 유용합니다. 메일을 보내는 작업은 네트워크 지연이나 메일 서버의 처리 시간 때문에 몇 초에서 몇 분까지 걸릴 수 있는데, 이를 메인 스레드에서 동기적으로 처리하게 되면 그 시간 동안 애플리케이션이 블록되어 사용자의 다른 요청을 처리할 수 없게 됩니다. 대신 @Async를 사용하면, 메일을 보내는 작업을 백그라운드에서 처리하고, 메인 스레드는 다른 요청을 계속 처리할 수 있습니다.

비동기 메서드를 사용하기 위한 설정

  • @EnableAsync 어노테이션 추가 : 스프링 부트 애플리케이션에 @EnableAsync를 추가하여 비동기 지원을 활성화한다. 이는 보통 메인 애플리케이션 클래스나 설정 클래스에 추가한다.
  • 비동기 메서드 설정 : @Async 어노테이션을 비동기적으로 실행하고자 하는 메서드에 추가한다.

🎈 @Async를 사용할 때의 주의사항은, 비동기 작업이 실패하거나 예외를 발생시켰을 때 이를 처리하는 방법을 고려해야 한다는 점. 예외 처리와 결과 모니터링에 대한 추가적인 로직이 필요할 수 있다.

sendMailMime 메서드 분석

JavaMailSender, MimeMessageHelper를 사용하여 이메일을 구성한다.

  1. createMimeMessage를 통해 MimeMessage 인스턴스를 생성
  2. MimeMessageHelper를 사용하여 수신자, 발신자, 제목 및 본문을 설정
  • setText메서드의 두번째 인자가 true라면, HTML 내용을 보낼 수 있다. ( 현재는 false라서 텍스트만 보냄)
  1. javaMailSender의 send메소드를 통해 이메일 전송

spring.mail 속성

이메일을 보내기 위해 spring.mail 속성을 사용하는 경우, JavaMailSender를 통해 이메일을 보내는 과정에서 이러한 설정이 자동으로 적용된다. 여기서 spring.mail.username, spring.mail.password가 자동으로 적용 !
(위 내용이 기본 발신자 주소와 인증 정보로 활용된다.)

  • 그러므로 to(수신자 주소), text(이메일 본문), subject(이메일 제목)만 지정해주면 된다.

  • 위 과정을 MimeMessageHelper를 통해 구성하면 된다.

비동기로 할꺼면 널처리 어떻게 할 지 생각해야함. 아니면 그냥 void로 진행.

  • 이후에 관련 내용 또 공부해보자.

ref.스프링 이메일 발송

profile
back-end, 지속 성장 가능한 개발자를 향하여

0개의 댓글