๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Project/์‹นํ‹”์›€

[์‹นํ‹”์›€] 11/07 ๊ฐœ๋ฐœ์ผ์ง€ ํšŒ์›๊ฐ€์ž…์‹œ ์ด๋ฉ”์ผ ์ธ์ฆ ๋ฐ›๊ธฐ 1 : ์ด๋ฉ”์ผ ์ธ์ฆ์ฝ”๋“œ ์ „์†ก

by ํ•œ33 2024. 11. 10.

๐Ÿ’ก ๋ชฉํ‘œ

ํšŒ์›๊ฐ€์ž…์‹œ์— ์ด๋ฉ”์ผ ์ธ์ฆ์„ ์ถ”๊ฐ€๋กœ ๋ฐ›์•„ ์ค‘๋ณต๋ฐฉ์ง€ ๋ฐ ๋ณด์•ˆ์„ฑ ๊ฐ•ํ™”๋ฅผ ๋ชฉ์ ์œผ๋กœ ๋‘์—ˆ๋‹ค.

 

build.gradle

// Google Email
implementation 'org.springframework.boot:spring-boot-starter-mail'

 

์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•ด์ค€๋‹ค.


EmailConfig

@Slf4j
@Configuration
@RequiredArgsConstructor
public class EmailConfig {

    private final JavaMailSender javaMailSender;

    private final String SUBJECT = "[์‹นํ‹”์›€] ์ธ์ฆ๋ฉ”์ผ ์ž…๋‹ˆ๋‹ค.";

    public boolean sendCertificationMain(String email, String certificationNumber) {

        try {
            MimeMessage message = javaMailSender.createMimeMessage();
            MimeMessageHelper messageHelper = new MimeMessageHelper(message, true);

            String htmlContent = getCertificationMessage(certificationNumber);

            messageHelper.setTo(email);
            messageHelper.setSubject(SUBJECT);
            messageHelper.setText(htmlContent, true);

            javaMailSender.send(message);

            log.info("์ด๋ฉ”์ผ ๋ฐœ์‹  ์„ฑ๊ณต : {}", email);

        } catch (Exception e) {
            log.error("์ด๋ฉ”์ผ ๋ฐœ์‹  ์‹คํŒจ : {}", email, e);
            return false;
        }
        return true;
    }

        private String getCertificationMessage (String certificationNumber) {
            String certificationMessage = "";
            certificationMessage += "<div style='text-align: center;'><img src=\"https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVbXC4%2FbtsKePF4r6K%2FHdV3AU33uDf8khBSMLMLU0%2Fimg.png\"></div>";
            certificationMessage += "<h1 style='text-align: center;'>[์‹นํ‹”์›€] ์ธ์ฆ๋ฉ”์ผ</h1>";
            certificationMessage += "<h3 style='text-align: center;'>์ธ์ฆ์ฝ”๋“œ: <string style='font-size:32px; letter-spacing: 8px;'>"
                    + certificationNumber + "</strong></h3>";
            return certificationMessage;
        }
    }

 

์ด๋ฉ”์ผ์„ ์ „์†กํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค.

getCertificationMessage ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด์„œ ์›ํ•˜๋Š” ํ˜•ํƒœ๋กœ ๋ฉ”์ผ์„ ๋งŒ๋“ค๊ณ , SUBJECT ์ œ๋ชฉ๊ณผ ํ•จ๊ป˜ ๋ฉ”์ผ์„ ์ „์†กํ•œ๋‹ค.


EmailCertificationController

@RestController
@RequiredArgsConstructor
public class EmailCertificationController {

    private final EmailCertificationService emailCertificationService;

    @PostMapping("/v2/auth/email-certification")
    public ResponseEntity<CommonResponse<String>> emailCertification(
            @RequestBody @Valid
            EmailCertificationRequestDto requestDto
    ) {
        return ResponseEntity.ok(CommonResponse.success(emailCertificationService.emailCertification(requestDto)));
    }
}

EmailCertificationRequestDto

@Getter
@NoArgsConstructor
public class EmailCertificationRequestDto {

    @Email
    @NotBlank
    private String email;
}

 

์ด๋ฉ”์ผ์„ Dto ์— ๋‹ด์•„์„œ ์ธ์ฆ๋ฒˆํ˜ธ๋ฅผ ๋‚ ๋ ค์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— email ํ•˜๋‚˜๋งŒ ๋‹ด์•˜๋‹ค.


EmailCertificationService

@Service
@RequiredArgsConstructor
public class EmailCertificationService {

    private final EmailConfig emailConfig;

    private final UserService userService;

    public String emailCertification(EmailCertificationRequestDto requestDto) {
        // ์ž…๋ ฅํ•œ ์ด๋ฉ”์ผ๋กœ ์ค‘๋ณต ์œ ๋ฌด ํ™•์ธ
        String email = requestDto.getEmail();
        boolean isExisted = userService.existsByEmail(email);
        if(isExisted) throw new DuplicateEmailException();

        // 4์ž๋ฆฌ ์ธ์ฆ๋ฒˆํ˜ธ ์ƒ์„ฑ
        String certificationNumber = getCertificationNumber();

        // ์ด๋ฉ”์ผ ๋ฐœ์‹  ์„ฑ๊ณต ์—ฌ๋ถ€ ํ™•์ธ
        boolean isSuccessed = emailConfig.sendCertificationMain(email, certificationNumber);

        // ์‹คํŒจ์‹œ ์˜ˆ์™ธ์ฒ˜๋ฆฌ
        if (!isSuccessed) throw new BusinessLogicException();


        return "์ด๋ฉ”์ผ์ด ์ •์ƒ์ ์œผ๋กœ ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค.";
    }

    // 4์ž๋ฆฌ ์ธ์ฆ๋ฒˆํ˜ธ ์ƒ์„ฑ ๋ฉ”์„œ๋“œ
    public static String getCertificationNumber() {
        String certificationNumber = "";
        for (int count = 0; count < 4; count++) {
            certificationNumber += (int) (Math.random() * 10);
        }

        return certificationNumber;
    }
}

 

๊ธฐ์กด ์ด๋ฉ”์ผ๊ณผ ์ค‘๋ณต์ธ์ง€ ํ™•์ธํ•˜๊ณ , ์ค‘๋ณต๊ฒ€์‚ฌ์—์„œ ํ†ต๊ณผํ•œ๋‹ค๋ฉด 4์ž๋ฆฌ ์ธ์ฆ๋ฒˆํ˜ธ๋ฅผ ๋žœ๋ค์œผ๋กœ ์ƒ์„ฑํ•ด์„œ ๋ฉ”์ผ์„ ์ „์†ก์‹œ์ผฐ๋‹ค.


๐Ÿ’ก ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

 

TLS ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

"Could not convert socket to TLS"  ์˜ค๋ฅ˜๋Š” ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ๊ฐ„ SSL/TLS ํ•ธ๋“œ์…ฐ์ดํฌ ์‹คํŒจ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•œ๋‹ค.

์ฃผ๋กœ ์ž˜๋ชป๋œ ์ธ์ฆ์„œ ์„ค์ •์ด๋‚˜ ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ ๋ฌธ์ œ๊ฐ€ ์›์ธ์ด๋‹ค.

 

properties:
  mail:
    smtp:
      auth: true
      starttls:
        enable: true
        required: true
      ssl:
        trust: smtp.gmail.com

 

starttls : required : true
ssl: truest ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด์„œ ํ•ด๊ฒฐ์ด ๋˜์—ˆ๋‹ค.

 

 

  • starttls.required=true:
    • ์ด ์„ค์ •์€ SMTP ์„œ๋ฒ„์™€์˜ ํ†ต์‹ ์— TLS๊ฐ€ ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•จ์„ ์ง€์ •ํ•œ๋‹ค.
    • ์ด๋ฅผ ํ†ตํ•ด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์™€ ๋ฐ˜๋“œ์‹œ ์•”ํ˜ธํ™”๋œ ํ†ต์‹ ์„ ํ•˜๋„๋ก ๊ฐ•์ œํ•ด, TLS ํ•ธ๋“œ์…ฐ์ดํฌ ์‹คํŒจ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ssl.trust=smtp.gmail.com:
    • ์ด ์„ค์ •์€ Gmail์˜ SMTP ์„œ๋ฒ„ ์ธ์ฆ์„œ๋ฅผ ์‹ ๋ขฐํ•˜๋„๋ก ์ง€์ •ํ•œ๋‹ค.
    • Gmail ์„œ๋ฒ„์™€์˜ ์—ฐ๊ฒฐ์—์„œ ์ธ์ฆ์„œ ์‹ ๋ขฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๋ฅผ ํ†ตํ•ด ํด๋ผ์ด์–ธํŠธ๊ฐ€ Gmail์˜ ์ธ์ฆ์„œ๋ฅผ ์‹ ๋ขฐํ•˜๊ฒŒ ๋˜์–ด TLS ์„ค์ •์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง„๋‹ค.

 

 

๋‹ค์Œ ๊ธ€

https://hanstory33.tistory.com/259