Spring Boot 메일 발송

최민길(Gale)·2023년 1월 16일
3

Spring Boot 적용기

목록 보기
12/46

안녕하세요 오늘은 Spring Boot에서 메일을 발송하는 방법에 대해서 포스팅하도록 하겠습니다. 현재 투다에는 메일로 비밀번호 찾기 기능을 제공하고 있는데, 이 부분을 Spring Boot에서 어떤 식으로 구현할 지 알아보도록 하겠습니다.

먼저 메일이 어떤 방식으로 발송되는지 동작 원리에 대해 간단하게 알아보겠습니다. A가 B에게 메일을 전송할 때

  1. A가 user agent를 통해 B에게 메일 내용을 작성하고 전송 버튼을 누른다.
  2. A의 user agent는 메시지를 A의 메일 서버에 보내고, 메시지는 메일 서버의 output message queue에 위치한다.
  3. A의 메일 서버에서 동작하는 SMTP 클라이언트는 output message queue에 쌓여 있는 메시지를 B의 메일 서버로 전송하기 위해 서버 SMTP의 25번 포트(대체 포트 : 587)로 TCP 연결을 맺는다.
  4. TCP 통신 후 SMTP 핸드쉐이킹을 진행한다. 이 과정에서 A의 SMTP 클라이언트는 송신자와 수신자의 이메일 주소를 제공한다.
  5. SMTP 핸드쉐이킹 후 SMTP 프로토콜에 따라 B의 메일 서버로 데이터를 전송한다.
  6. B의 메일 서버는 메시지를 수신한 후 그 메시지를 B의 메일 박스에 넣는다.
  7. B는 user agent를 실행하여 메일을 읽는다.

의 방식으로 동작합니다. SMTP 프로토콜은 HTTP와 유사하게 데이터 전송 시 클라이언트처럼 동작하고, 데이터를 수신 시 서버처럼 동작합니다. HTTP와의 차이점은 SMTP의 경우 한글이나 binary 데이터 처럼 ASCII가 아닌 문자를 포함한다면 반드시 이 메시지는 전송되기 전에 7bit ASCII로 인코딩이 되어야 합니다.

추가적으로 user agent에서 메시지를 가져오는 방식은 SMTP 프로토콜로 사용하지 않습니다. SMTP 프로토콜은 푸시용 프로토콜이기 때문에 POP3, IMAP 등의 메일 접속 프로토콜을 이용하여 메일을 가져옵니다.

    // Mail
    implementation "org.springframework.boot:spring-boot-starter-mail"

그럼 지금부터 Spring Boot에서 메일 기능을 구현해보겠습니다. 우선 build.gradle에 다음과 같은 dependency를 추가해줍니다.

#Mail
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username={이메일 주소}
spring.mail.password={구글 2단계 인증 앱 비밀번호}
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

이번 테스트는 587 포트 SMTP 프로토콜을 통해 gmail을 이용하여 메일을 전송해보도록 하겠습니다. gmail의 경우 메일을 발송하는 방법은 크게 2가지 입니다. 우선 첫 번째로 계정의 보안 수준을 낮춰 외부에서 접근 가능하도록 하는 방법이 있고, 두 번째로 2단계 인증 후 앱 비밀번호를 발급받아 진행하는 방법이 있습니다. 저는 보안을 위해 후자의 방법을 택했습니다.

package com.example.test.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;

import java.util.Properties;

@Configuration
public class MailConfig {

    @Value("${spring.mail.host}")
    public String host;

    @Value("${spring.mail.port}")
    public int port;

    @Value("${spring.mail.username}")
    public String sendEmail;

    @Value("${spring.mail.password}")
    public String sendPassword;

    @Value("${spring.mail.properties.mail.smtp.auth}")
    public boolean auth;

    @Value("${spring.mail.properties.mail.smtp.starttls.enable}")
    public boolean starttlsEnable;

    @Bean
    public JavaMailSender getJavaMailSender() {
        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
        mailSender.setHost(host);
        mailSender.setPort(port);
        mailSender.setUsername(sendEmail);
        mailSender.setPassword(sendPassword);

        Properties props = mailSender.getJavaMailProperties();

        props.put("mail.transport.protocol", "smtp");
        props.put("mail.smtp.auth", auth);
        props.put("mail.smtp.starttls.enable", starttlsEnable);
        props.put("mail.debug", "true");

        return mailSender;
    }

}

이어서 MailConfig 파일을 만든 후 JavaMailSender에 @Bean을 통해 의존성을 주입해줍니다. 내부에 application.properties에서 설정한 메일 정보를 @Value를 이용하여 가져옵니다.

	...
    @Autowired
    private JavaMailSender emailSender;
    ...
    
    ...
    SimpleMailMessage message = new SimpleMailMessage();
    message.setTo({메일을 보내려는 이메일 주소});
    message.setSubject("테스트 메일");
    message.setText("테스트 메일");
    emailSender.send(message);
    ...

이후 SimpleMailMessage 객체를 이용하여 메일의 정보를 추가하여 JavaMailSender를 이용하여 메일을 전송합니다.

테스트를 진행하면 다음과 같이 콘솔에 메일 발송 로그를 확인하실 수 있습니다.

메일 역시 성공적으로 발송되었습니다. 현재는 로컬 환경에서 진행해서 구글 2단계 비밀번호를 Mac 용으로 발급받았는데 EC2 위에서 전송 시 앱 비밀번호를 어떻게 발급받아야 할 지 추후 다시 진행해보고 포스팅하겠습니다. 긴 글 읽어주셔서 감사합니다!

출처
: https://tk-one.github.io/2020/01/03/smtp/
: https://www.baeldung.com/spring-email
: https://born2bedeveloper.tistory.com/14

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글