Spring

[Spring] Spring Boot 이메일 인증 구현하기 + Redis (1)

코냥이 2024. 1. 25. 20:03

 

 

 

 

들어가기

SpringBoot와 Redis를 사용해서 이메일 인증하는 API를 구현하려고 한다.

차근차근 시작해보자 !!

 

 

 

 

 

💡 Google SMTP


본 포스팅에서는 Google SMTP를 사용할 것이다.

SMTP(Simple Mail Transfer Protocol)란?
: 전자 메일 전송을 위한 표준 프로토콜이다. 즉, 인터넷에서 이메일을 전송하기 위해 사용되는 프로토콜이다.

Google SMTP는 구글에서 구글 계정만 있으면 무료로 메일을 발송할 수 있도록 제공해 주는 서버이다.

이메일 인증 코드를 전송해 주는 API를 위해 Google SMTP를 사용할 것이다.

 

 

먼저, SMTP를 사용할 구글 계정을 설정해주어야 한다.

 

 

✔️ Google SMTP 계정 설정

구글 계정에 로그인한 후, Google 계정 관리에 들어가서 검색창에 앱 비밀번호를 검색한다.

* 2단계 인증이 진행된 후에 설정할 수 있다. 2단계 인증을 하지 않았다면 먼저 인증하고 나서 하자!

앱 비밀번호 검색하기

 

앱 비밀번호를 검색하면 아래와 같은 화면이 나올 것이다. 여기에 앱 이름을 작성한다. 

앱 이름 설정하기

 

앱 이름을 만들면 앱 비밀번호가 생성될 것이다. 복사해서 잘 보관해 두자!

앱 비밀번호는 외부에 노출되어서는 절대절대 안 된다. 주의!!

앱 비밀번호 확인

 

비밀번호를 잘 보관한 후에, Gmail -> 설정 -> 전달 및 POP/IMAP 탭에 들어간다.

아래와 같이 POP 설정을 하고, IMAP를 사용하도록 설정한다.

 

 

여기까지 구글 계정 설정은 끝이다!

 

 

 

 

 

💡 이메일 인증 요청 API 구현하기


구글 계정 설정을 잘 마쳤다면 이제 Spring Boot를 통해 API를 구현해 보자.

 

1. build.gradle

이메일 전송을 위해 Spring boot에서 지원해주는 mail 의존성을 추가한다.

// 이메일 전송을 위한 의존성
implementation 'org.springframework.boot:spring-boot-starter-mail'

 

 

2. application.yml

spring:
    mail:
    host: smtp.gmail.com
    port: 587
    username: 구글 계정
    password: 구글 앱 비밀번호
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
  • host : Gmail의 SMTP 서버 호스트
  • port : SMTP 서버의 포트 번호로, Google은 587을 사용한다.
  • username : Google SMTP 설정한 구글 아이디
  • password : Google SMTP 설정에서 발급받은 앱 비밀번호
  • properties : 이메일 구성에 대한 추가 설정들
  • auth : SMTP 서버에 인증을 요구하면 true로 설정해야 한다. Gmail SMTP 서버는 인증을 요구하기 때문에 true로 설정한다.
  • enable : SMTP 서버가 TLS(데이터를 암호화하여 안전한 전송을 보장하는 프로토콜)를 사용하면 true로 설정한다.

 

 

3. EmailConfig

@Configuration
public class EmailConfig {

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

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

    @Value("${mail.username}")
    private String userName;

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

    @Value("${mail.properties.mail.smtp.auth}")
    private boolean smtpAuth;

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

    @Value("${mail.properties.mail.smtp.starttls.required}")
    private boolean starttlsRequired;

    @Bean
    public JavaMailSender javaMailSender() {
        JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();

        javaMailSender.setHost(host);
        javaMailSender.setPort(port);
        javaMailSender.setUsername(userName);
        javaMailSender.setPassword(password);
        javaMailSender.setJavaMailProperties(getMailproperties());
        javaMailSender.setDefaultEncoding("UTF-8");

        return javaMailSender;
    }

    private Properties getMailproperties() {
        Properties properties = new Properties();

        properties.put("mail.smtp.auth", smtpAuth);
        properties.put("mail.smtp.starttls.enable", starttlsEnable);
        properties.put("mail.smtp.starttls.required", starttlsRequired);

        return properties;
    }
}

 

 

4. EmailService

@Slf4j
@Service
public class EmailService {

    private final JavaMailSender javaMailSender;

    private String emailCode;

    public EmailService(JavaMailSender javaMailSender) {
        this.javaMailSender = javaMailSender;
    }

    @Transactional(readOnly = false)
    public DataResponse<DataResponseCode> sendMail(String receiver) {
        try {
			emailCode = createKey();
            MimeMessage message = createMessage(receiver);

            javaMailSender.send(message);

            return new DataResponse<>(UserSignUpResponseCode.SUCCESS);
        } catch (MessagingException | UnsupportedEncodingException | MailException e) {
            e.printStackTrace();
            return new DataResponse<>(UserSignUpResponseCode.MAIL_SEND_FAILED);
        }
    }

    /**
     *  메일 내용 작성
     */
    private MimeMessage createMessage(String receiver) throws MessagingException, UnsupportedEncodingException {
        MimeMessage message = javaMailSender.createMimeMessage();

        message.addRecipients(Message.RecipientType.TO, receiver);
        message.setSubject("인증코드 안내");

        StringBuilder mailMsg2 = new StringBuilder();
        mailMsg2.append("<div>");
        mailMsg2.append("인증코드를 확인해주세요.<br><strong style=\"font-size: 30px;\">");
        mailMsg2.append(emailCode);
        mailMsg2.append("</strong><br>이메일 인증 절차에 따라 이메일 인증코드를 발급해드립니다.<br>인증코드는 이메일 발송 시점으로부터 3분동안 유효합니다.</div>");

        message.setText(mailMsg2.toString(), "utf-8", "html");
        message.setFrom(new InternetAddress("myApp", "MY APP"));

        return message;
    }

    /**
     *  메일 인증 코드 생성
     */
    private static String createKey() {
        StringBuilder key = new StringBuilder();

        Random random = new Random();

        for (int i = 0; i < 6; i++) {
            int index = random.nextInt(10);
            key.append(index);
        }

        return key.toString();
    }
}

 

 

5. EmailController

@RestController
@RequestMapping("/api/v1/mail")
public class EmailController {

    private final EmailService emailService;

    public EmailController(EmailService emailService) {
        this.emailService = emailService;
    }

    @GetMapping(name = "이메일 전송")
    public DataResponse<DataResponseCode> sendMail(@RequestParam("receiver") String receiver) {
        DataResponse<DataResponseCode> response = emailService.sendMail(receiver);
        return response;
    }

}

 

 

6. 결과 확인하기

API 테스트를 해보면 아래와 같이 정상적으로 메일이 전송되는 것을 확인할 수 있다.

 

 

 

 

다음 포스팅에서 Redis로 인증코드 만료 로직을 처리하는 코드를 추가할 것이다!

 

 

 

 

출처

 

 

 

긴 글 읽어주셔서 감사합니다 🍀

잘못 작성된 내용은 피드백 주시면 반영하겠습니다 😎