Amazon SES를 통해 메일보내기 시리즈
- Amazon SES 사용하여 메일 보내기 (1) - SES란?
- Amazon SES 사용하여 메일 보내기 (2) - 아마존 SES 설정
- Amazon SES 사용하여 메일 보내기 (3) - 이메일 인증 기능 with Spring & AWS SDK for Kotlin - 현재글
이 글에서는 이메일 인증 설정을 아~~~~~~~~주 간단하게 구현해볼 것이다. 사실 가능하다면 이 글보다 더 잘 쓰여진 글, 공식 문서가 존재하기 때문에 그것을 보는 것이 더 도움이 될 것이라 확신한다. 아래처럼 언어별로 설명서와 코드 예제가 있으므로 확인해보면 좋을 것 같다.
이메일 인증 기능 개발 시작
저는 SDK를 사용할 것이기 때문에 gradle.build.kts에 다음과 같이 의존성을 주입한다.
dependencies {
...
//aws ses
implementation("aws.sdk.kotlin:ses:0.16.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
...
}
코루틴을 넣는 이유는 AWS SDK for Kotlin이 코루틴을 사용하여 만들어졌기 때문이다.
Access Key 넣기
Access Key 발급 방법이 궁금하다면 다음 링크에서 받아와 application.yml 이나 환경 변수에 넣어주면된다.
[AWS] IAM - Access Key 발급 받기
처음 AWS 프리티어를 만들고 SDK를 통해 AWS를 사용하려면 인증을 위해 Access Key가 필요하다. 이 글에서는 그 방법을 정리해보고자 한다. 먼저 IAM이란? IAM(AWS Identity and Access Management)은 AWS 리소스에
dul2.tistory.com
# application.yml
aws:
access-key: {AWS accesskey}
secret-key: {AWS secretkey}
sender-email: {발신자 이메일 주소}
SES와 통신을 위한 Client 클래스
이제 AWS SES와 통신을 해서 메일 전송 요청만 할 수 있도록 Client 클래스를 만들면 끝이다.
package com.sparta.reviewus.common
import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider
import aws.sdk.kotlin.services.ses.SesClient
import aws.sdk.kotlin.services.ses.model.*
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
@Component
class SESClient(
@Value("\${aws.access-key}") private val accessKey: String,
@Value("\${aws.secret-key}") private val secretKey: String,
@Value("\${aws.sender-email}") private val senderEmail: String,
) {
suspend fun sendVerificationCodeMailTo(recipient: String): Int {
val sender = senderEmail
val code = generateRandomCode()
val subject = "ReviewUs 이메일 인증 확인"
val bodyHTML = (
"<html>" + "<head></head>" + "<body>" +
"<h3>" + "요청하신 인증 번호입니다." + "</h3>" +
"<h1>$code</h1>" +
"<h3>" + "감사합니다." + "</h3>" +
"</body>" + "</html>"
)
send(sender, recipient, subject, bodyHTML)
return code
}
suspend fun send(
sender: String?,
recipient: String,
subjectVal: String?,
bodyHTML: String?
) {
val destinationOb = Destination {
toAddresses = listOf(recipient)
}
val contentOb = Content {
data = bodyHTML
}
val subOb = Content {
data = subjectVal
}
val bodyOb = Body {
html = contentOb
}
val msgOb = Message {
subject = subOb
body = bodyOb
}
val emailRequest = SendEmailRequest {
destination = destinationOb
message = msgOb
source = sender
}
SesClient {
region = "ap-northeast-2"
credentialsProvider = StaticCredentialsProvider {
accessKeyId = accessKey
secretAccessKey = secretKey
}
}.use { sesClient ->
println("Amazon SES에 AWS SDK for Kotlin을 이용하여 메일 전송 시도중 ...")
sesClient.sendEmail(emailRequest)
}
}
companion object {
fun generateRandomCode(): Int {
return (Math.random() * (90000)).toInt() + 100000 // (int) Math.random() * (최댓값-최소값+1) + 최소값
}
}
}
인증 요청 메일 기능만 만들었기 때문에 간단하고 인증 메일에 보낼 Body 값은 bodyHTML를 원하는대로 변경해주면 된다.
위 클라이언트를 사용해 각자 원하는 계층을 구성하여 기능을 구현하면 된다.
위 메소드는 인자로 보낼 이메일 주소를 받으며 랜덤 코드를 만들어 보내는 역할을 한다. suspend가 걸려있는 이유는 aws sdk가 코루틴을 기반으로 작동하기 때문에 걸어주어야 한다.
실제 SES와 통신하는 메서드는 send 메서드가 해준다.
send 메서드에서 눈여겨 봐야할 점은 아래 region 값인데 만약 본인이 서울이 아닌 다른 서버를 사용한다면 알맞게 변경해주어야 한다.(이 또한 application.yml로 빼주어도 된다.)
RX를 이용해 메일 수신까지 만들고 싶다면 아마 다른 region을 선택했을 것이다.
sendEmail 메서드를 통해 메일 요청을 AWS SES로 보내게 된다.
Mail Service
본인은 메일 서비스를 다음과 같이 3개의 메서드로 구분했다.
- saveVerificationCode - 생성된 코드를 추후 확인하기 위해 DB 저장하는 메서드
- checkEmailVerification - 유저가 이메일 인증을 요청하는 메서드
- checkValidation - 현재 보내려는 이메일이 이미 인증되었는지 확인하는 메서드
@Service
class MailService(
private val verifiedEmailRepository: VerifiedEmailRepository
) {
@Transactional
fun saveVerificationCode(email: String, code: Int) {
val findVerifiedEmail = checkValidation(email)
findVerifiedEmail.code = code
}
@Transactional
fun checkEmailVerification(email: String, code: Int) {
val findVerifiedEmail = checkValidation(email)
if (findVerifiedEmail.code != code) throw EmailVerificationFailedException("알맞은 인증 코드를 입력해주세요.")
findVerifiedEmail.isVerified = true
}
private fun checkValidation(email: String): VerifiedEmail {
val findVerifiedEmail = verifiedEmailRepository.findVerifiedEmailByEmail(email) ?: throw EmailVerificationFailedException("먼저 회원가입을 해주세요!")
if (findVerifiedEmail.isVerified) throw EmailAlreadyVerifiedException(email)
return findVerifiedEmail
}
}
Mail Controller
실제 SesClient 는 컨트롤러에서 요청하게 된다. 메일 전송할 때 코드가 만들어지므로 이 코드를 서비스로 보내는 방식으로 구현했다.
import com.sparta.reviewus.api.aop.IsAuthenticated
import com.sparta.reviewus.domain.member.service.MailService
import com.sparta.reviewus.common.SESClient
import com.sparta.reviewus.domain.member.dto.AuthenticatedMember
import io.swagger.v3.oas.annotations.Parameter
import kotlinx.coroutines.runBlocking
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping("/mail")
class MailController(
private val mailService: MailService,
private val sesClient: SESClient
) {
@IsAuthenticated
@PostMapping("/requestCode")
fun mailVerification(
@Parameter(hidden = true) authenticatedMember: AuthenticatedMember
): ResponseEntity<String> {
return runBlocking {
println("${authenticatedMember.email} 에게 메일 전송 시도 중")
sesClient.sendVerificationCodeMailTo(authenticatedMember.email).let {
mailService.saveVerificationCode(authenticatedMember.email, it)
ResponseEntity
.status(HttpStatus.OK)
.body("이메일 인증 번호 전송 완료!")
}
}
}
@IsAuthenticated
@PostMapping("/verification")
fun mail(
@RequestParam code: Int,
@Parameter(hidden = true) authenticatedMember: AuthenticatedMember
): ResponseEntity<String> {
mailService.checkEmailVerification(authenticatedMember.email, code)
return ResponseEntity
.status(HttpStatus.OK)
.body("이메일 인증 완료!")
}
}
이메일 인증 메일 전송 테스트
메일이 전송되고 나면 다음과 같은 인증 메일 번호가 메일로 날라온다.
더 부가적인 기능이 궁금하다면 AWS SDK 깃허브나 문서를 참고해보면 좋을 것 같다. 테스트 코드와 정보들이 존재한다.
https://aws.amazon.com/ko/sdk-for-kotlin/
AWS SDK for Kotlin – Software Development Kit – Amazon Web Services
The AWS SDK for Kotlin simplifies the use of AWS services by providing a set of libraries that are consistent and familiar for Kotlin developers. All AWS SDKs support API lifecycle considerations such as credential management, retries, data marshaling, and
aws.amazon.com
마무리
직접 만들고 공부할 때는 엄청 오래 걸리고 막상 에러가 많이 터졌지만 막상 글을 작성하고 보니 개발 자체 코드는 길지 않다. ㅜㅜ
sdk를 사용해 단순히 그냥 메일 전송 기능만 사용하다보니 s3에 비해 코드 양이 적은 것도 있는 것 같다. 다음에 기회가 되면 s3에 관한 포스트도 작성해보면 좋을 것 같다.
그래도 오랜만에 내 도메인부터 AWS 계정 사용 방법까지 다시 정리해보면서 복습해보는 시간이 되어 좋은 경험이었던 것 같다.
'Infra > Cloud' 카테고리의 다른 글
[AWS] IAM - Access Key 발급 받기 (0) | 2024.01.14 |
---|---|
Amazon SES 사용하여 메일 보내기 (2) - 아마존 SES 설정 (0) | 2024.01.14 |
Amazon SES 사용하여 메일 보내기 (1) - SES란? (0) | 2024.01.14 |
Ubuntu - Hostname 변경하기 (0) | 2022.09.20 |
ubuntu ec2 시스템 시간 바꾸기 (0) | 2022.09.13 |