회원가입을 하면 이메일로 회원가입 성공 메시지를 전송할 수 있다!
전체 로직: 클라이언트 > Controller Post 요청 > Service의 회원가입 로직 > Event 발행 > Email 전송 로직 실행
0. Google 앱 비밀번호 발급
Google 계정 관리 > 2단계 인증 활성화 > 앱 비밀번호 > 메일, Windows 컴퓨터로 지정하고 발급
1. 의존성 추가
//build.gradle
implementation 'org.springframework.boot:spring-boot-starter-mail'
2. Gmail SMTP 설정 추가
//application-local.yml
mail:
smtp:
host: smtp.gmail.com
port: 587
username: ${EMAIL_USERNAME} //Gmail email
password: ${EMAIL_PASSWORD} //Google 계정 2단계 인증 생성 후 앱 비밀번호 생성
auth: true
starttls:
enable: true //일부 SMTP 서버에는 TLS 연결이 필요하므로 TLS 보호 연결을 활성화한다
subject:
member:
registration: Thank you for joining our cafe!
3. 메일 전송을 위한 구성
- 📗 MailSender: 이메일 전송을 위한 기본 기능을 제공하는 최상위 인터페이스이다.
- 📗 JavaMailSender: MailSender의 하위 인터페이스
MIME 메시지를 지원하며 이를 생성하기 위해 MimeMessageHelper 클래스와 함께 사용된다. - 📄 JavaMailSendImpl: MimeMessage 및 SimpleMailMessage를 지원한다.
SMTP 서버를 지정하는 데에 필요한 메일 속성을 정의한다. - 📄 SimpleMailMessage: 보낸 사람, 받는 사람, 참조, 제목 및 텍스트를 포함하는 메시지를 만드는 데에 사용된다.
- 📗 MimeMessagePreparator: MIME 메시지 준비를 위한 콜백 인터페이스이다.
- 📄 MimeMessageHelper: MIME 메시지 생성을 위한 도우미 클래스이다. HTML 레이아웃 등의 지원을 제공한다.
📄 MemberRegistrationEventListener
회원 가입 요청이 들어오면 EamilSender의 sendEmail 메서드에 이메일, 제목, 메시지를 파라미터로 넘긴다.
@EnableAsync
@Configuration
@Component
@Slf4j
public class MemberRegistrationEventListener {
@Value("${mail.subject.member.registration}") //"Thank you for joining our cafe!" 메시지 주입
private String subject;
private final EmailSender emailSender;
private final MemberService memberService;
public MemberRegistrationEventListener(EmailSender emailSender, MemberService memberService) {
this.emailSender = emailSender;
this.memberService = memberService;
}
@Async
@EventListener
public void listen(MemberRegistrationApplicationEvent event) throws Exception {
try {
String[] to = new String[]{event.getMember().getEmail()};
String message = event.getMember().getEmail() + "님, 회원 가입이 성공적으로 완료되었습니다.";
emailSender.sendEmail(to, subject, message);
} catch (MailSendException e) {
e.printStackTrace();
log.error("MailSendException: rollback for Member Registration:");
Member member = event.getMember();
memberService.deleteMember(member.getMemberId());
}
}
}
📄 EmailSender
sendEmail 메서드는 EmailSendable의 send 메서드를 호출한다.
@Service
public class EmailSender {
private final JavaMailSender mailSender;
private final EmailSendable emailSendable;
public EmailSender(JavaMailSender mailSender, EmailSendable emailSendable) {
this.mailSender = mailSender;
this.emailSendable = emailSendable;
}
public void sendEmail(String[] to, String subject, String message) throws MailSendException, InterruptedException {
emailSendable.send(to, subject, message);
}
}
📗 EmailSendable
이메일 전송을 위한 기본 기능을 제공하는 최상위 인터페이스이다.
구현체: MockEmailSendable, MockExceptionEmailSendable, SimpleEmailSendable, TemplateEmailSendable
@Component
public interface EmailSendable {
void send(String[] to, String subject, String message) throws InterruptedException;
}
📄 SimpleEmailSendable
첨부 파일 없이 간단한 이메일 메시지를 작성한다. 많은 SMTP 서버에서는 from address를 제공하지 않으면 메시지를 거부한다.
@Slf4j
public class SimpleEmailSendable implements EmailSendable {
private final JavaMailSender javaMailSender;
public SimpleEmailSendable(JavaMailSender javaMailSender) {
this.javaMailSender = javaMailSender; //MailSender 인터페이스를 상속받으며, MIME을 지원한다
}
@Override
public void send(String[] to, String subject, String message) {
// 보낸 사람, 받는 사람, 참조, 제목 및 텍스트를 포함하는 메시지를 만든다
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setTo(to); //받는 사람 주소
mailMessage.setText(message); //보내는 사람 주소(호출하지 않으면 yml의 username으로 세팅)
mailMessage.setSubject(subject); //제목
mailMessage.setText(message); //메시지 내용
javaMailSender.send(mailMessage); //메일 발송
log.info("Sent simple email!");
}
}
📚 Reference
- Google 앱 비밀번호 발급
- Read Gmail messages on other email clients using POP
- Baeldung : Guide to Spring Email
- GeeksforGeeks : Spring Boot - Sending Email via SMTP
대략적인 흐름은 파악했으나, EmailSendable 구현 클래스들 각각의 이해가 더 필요함
'Back-End > Spring' 카테고리의 다른 글
[Spring Security] 웹 요청 처리 흐름, 서블릿 필터와 필터 체인 (0) | 2022.09.22 |
---|---|
[Spring Boot] JUnit으로 단위 테스트(Unit Test) 코드 작성하기 (0) | 2022.09.18 |
[Spring MVC] 애플리케이션 빌드 / 실행 / 배포 (0) | 2022.09.16 |
[Spring Boot] JUnit을 이용하여 테스트 코드 작성하기 (feat. Mockito) (0) | 2022.09.07 |
ApplicationEventPublisher: How to use events in Spring | @Async (0) | 2022.09.05 |
댓글