[Spring] Spring + AWS SDK Kotlin 이용하여 SES로 email 전송하기

kshired·2022년 9월 18일
1

Spring

목록 보기
10/11
post-thumbnail

이번 글에서는 AWS의 SES(Simple Email Service)를 사용하여, 이메일을 보낼 것입니다.

Java 버전의 SDK도 존재하지만, 이번에는 Kotlin 용으로 나온 AWS SDK Kotlin을 사용해보려고 합니다.

의존성 추가하기

implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
implementation("aws.sdk.kotlin:ses:0.16.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")

이메일을 보낼 때는, thymeleaf를 통해 html 템플릿 형태의 메일을 전송할 것이며 aws sdk kotlin을 사용할 것입니다.

aws sdk kotlin은 코루틴 방식으로 구현되어 있기 때문에 kotlinx-corutines 도 함께 추가해야합니다.

Thymeleaf 템플릿 구성

간단하게, 아래와 같은 인증번호를 받는 템플릿을 만들어보겠습니다.

html 만들기

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
        <div style="font-family: 'Apple SD Gothic Neo', 'sans-serif' !important; width: 540px; height: 600px; border-top: 4px solid #2A7AF3; margin: 100px auto; padding: 30px 0; box-sizing: border-box;">
            <h1 style="margin: 0; padding: 0 5px; font-size: 28px; font-weight: 400;">
                <span style="color: #2A7AF3">인증번호</span> 안내입니다.
            </h1>
            <p style="font-size: 16px; line-height: 26px; margin-top: 20px; padding: 0 5px;">
                아래 <b style="color: #2A7AF3">인증번호</b><b>5분내로</b> 입력해주세요.
            </p>

            <div style="color: #FFF; text-decoration: none; text-align: center;">
              <p style="display: inline-block; width: 210px; height: 45px; margin: 30px 5px 40px; background: #2A7AF3; line-height: 45px; vertical-align: middle; font-size: 16px;" th:text="${code}"></p>
            </div>

            <div style="border-top: 1px solid #DDD; padding: 5px;">
                <p style="font-size: 13px; line-height: 21px; color: #555;">
                    만약 버튼이 정상적으로 클릭되지 않는다면, 아래 링크를 복사하여 접속해 주세요.<br/>
                    아무에게도 이 링크를 공유하지마세요. 회원 정보가 유출되는 문제가 발생 할 수 있습니다.<br/>
                </p>
            </div>
        </div>
    </body>
</html>

th:text="${code}" 는 thymeleaf의 문법으로, code에 가변적인 값을 템플릿 형태로 넣어줄 수 있게 해줍니다.

위 template을 Spring의 src/main/resources/mail-templates 아래에 code.html 으로 저장해줍니다.

설정 값 넣기

spring:
    thymeleaf:
        prefix: classpath:/mail-templates/
        suffix: .html
        mode: HTML
        encoding: UTF-8
        check-template-location: true
        cache: false

위와 같이 thymeleaf를 위한 application.yml 설정 값을 세팅해줍니다.
이렇게 설정하면, 코드에서 src/main/mail-templates/ 에 존재하는 thymeleaf 템플릿을 가져올 수 있게 됩니다.

SES 사용하기

설정 값 세팅하기

aws:
    access-key: 액세스키
    secret-key: 시크릿키

위와 같이, application.yml 에 ses에 사용할 액세스키와 시크릿키를 넣어줍니다.

위 값들은, 아래 글을 보고 생성하면 됩니다.

https://lannstark.tistory.com/66

코드 구현하기

MailService

메일을 전송하는 비즈니스 로직이며, 간단하게 인증번호를 보내는 코드입니다.

package com.example.mail.service

import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
import aws.sdk.kotlin.services.ses.SesClient
import aws.sdk.kotlin.services.ses.model.Body
import aws.sdk.kotlin.services.ses.model.Content
import aws.sdk.kotlin.services.ses.model.Destination
import aws.sdk.kotlin.services.ses.model.Message
import aws.sdk.kotlin.services.ses.model.SendEmailRequest
import org.thymeleaf.context.Context
import org.thymeleaf.spring5.SpringTemplateEngine

@Service
class MailService(
    private val templateEngine: SpringTemplateEngine,

    @Value("\${aws.access-key}")
    private val accessKey: String,

    @Value("\${aws.secret-key}")
    private val secretKey: String
) {
	// coroutine이라 suspend
    suspend fun sendMail(to: String) {
    	// 인증번호 생성
        val code = generateRandomCode()
        
        // thymeleaf template에 사용 할 context 생성
        val context = Context()
        context.setValue("code", code)
        
        // email 요청 생성
        val emailRequest = SendEmailRequest {
        	// 메일 받는 사람 
            destination = Destination {
                toAddresses = listOf(to)
            }
            
            // 메일 메시지 생성
            message = Message {
            	// 메일 제목
                subject = Content {
                    data = "인증 번호"
                }
                
                // 메일 내용
                body = Body {
                    html = Content {
                    	// code.html에 인증번호 삽입
                        data = templateEngine.process("code", context)
                    }
                }
            }
            
            // 보내는 사람
            source = "no-reply@test.com"
        }
       
		// aws ses 를 이용하여 mail 전송
        SesClient {
        	// region 설정
            region = "ap-northeast-2"
            
            // aws 인증
            credentialsProvider = StaticCredentialsProvider {
                accessKeyId = accessKey
                secretAccessKey = secretKey
            }
        }.use {
        	// mail 전송
            it.sendEmail(emailRequest)
        }
    }
    
    // 인증번호 생성
    fun generateRandomCode(): String {
        return (1..5).map { (0..9).random() }.joinToString("")
    }
}

MailController

위에서 구현한 비즈니스 로직을 실행할 수 있도록, Controller에서 응답을 받도록 하였습니다.

@RestController
@RequestMapping("/api/mail")
class MailController(
	private val mailService: MailService
) {
    @GetMapping("/{mail}")
    fun sendPasswordChangeMail(@PathVariable("mail") mail: String): ApiResponse<String> {
        // 동기적인 Spring MVC의 특성상, runBlocking을 이용하여 suspend fun을 실행
        return runBlocking {
            mailService.sendMail(mail)
            ApiResponse.success("success")
        }
    }
}

결과 확인하기

사실 아까 위에서, 예시로 보여줬던 사진이 실제 결과입니다.

정말 깔끔하게 잘 갑니다.

주의점

AWS SES가 sendbox stage인 경우, AWS 팀에 연락을 하여 실 서비스에 쓸 수 있도록 해야합니다.

그렇지 않으면, 등록한 이메일로 밖에 못보내게됩니다.

profile
글 쓰는 개발자

0개의 댓글