- 이번 포스팅으론 Springboot 에서 JavaMailSender 를 사용하여 이메일을 보내는 예시를 정리할 것입니다.
백엔드 서비스 개발시 의외로 수요가 많은 기술로,
서비스 진행 상태 공유, 인증 관련 비밀 문서 제공, 광고성 정보제공 등의 용도로 사용되며,
Springboot 에서는 JavaMailSender 를 사용하여 쉽게 이메일을 전송 가능합니다.
- 진행하기 전에 필요한 사항이 있습니다.
HTML 이메일 전송을 위한 준비사항으로,
앞선 포스팅에서 작성했던 Thymeleaf HTML 을 HTML String 으로 변환해주는 함수를 준비해주셔야 합니다.
Thymeleaf 설정은 이미 되어있다고 가정하겠습니다.
- 먼저 build.gradle 안의 dependencies 에
// (Spring email)
// : 스프링 이메일 발송
implementation("org.springframework.boot:spring-boot-starter-mail:3.3.0")
위 라이브러리를 추가해주세요.
다음으로 application.yml 에 smtp 서버 관련 설정을 할 것입니다.
custom-config: # 프로젝트 내에서 사용하는 커스텀 설정
smtp: # SMTP 설정
host: smtp.gmail.com # SMTP 호스트
port: 587 # SMTP 포트
sender-name: InputYourEmailId@test.com # SMTP 계정 아이디
sender-password: InputYourSenderPassword # SMTP 계정 비밀번호
time-out-millis: 10000 # 타임아웃 밀리초
위와 같이 smtp 관련 정보들을 설정해주세요.
이는 제가 임의로 설정한 설정 형식으로, config 파일에서 이를 사용하여 이메일 전송 빈을 만들 것입니다.
바로 Springboot Config 빈을 등록할 것입니다.
MailConfig.kt 파일 안에,
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.mail.javamail.JavaMailSenderImpl
import java.util.*
// [JavaMail 설정]
@Configuration
class MailConfig(
@Value("\${custom-config.smtp.host}")
var host: String,
@Value("\${custom-config.smtp.port}")
var port: Int,
@Value("\${custom-config.smtp.sender-name}")
var senderName: String,
@Value("\${custom-config.smtp.sender-password}")
var senderPassword: String,
@Value("\${custom-config.smtp.time-out-millis}")
var timeOutMillis: String
) {
@Bean
fun javaMailSender(): JavaMailSenderImpl {
val mailSender = JavaMailSenderImpl()
mailSender.host = host
mailSender.port = port
mailSender.username = senderName
mailSender.password = senderPassword
val props: Properties = mailSender.javaMailProperties
props["mail.smtp.connectiontimeout"] = timeOutMillis
props["mail.smtp.timeout"] = timeOutMillis
props["mail.smtp.writetimeout"] = timeOutMillis
// SMTP 종류별 설정
// 보안 설정이 필요없는 상황이라면 아래 코드를 주석처리 하면 됩니다.
if (port == 587) {
// port 587 일 경우
props["mail.transport.protocol"] = "smtp"
props["mail.smtp.auth"] = "true"
props["mail.smtp.starttls.enable"] = "true"
props["mail.debug"] = "true"
} else if (port == 465) {
// port 465 일 경우
props["mail.smtp.ssl.enable"] = "true" // SSL 활성화
props["mail.smtp.auth"] = "true" // SMTP 인증 활성화
props["mail.smtp.connectiontimeout"] = "10000"
props["mail.smtp.timeout"] = "10000"
props["mail.smtp.writetimeout"] = "10000"
props["mail.smtp.ssl.checkserveridentity"] = "false"
props["mail.smtp.ssl.trust"] = "*"
}
return mailSender
}
}
위와 같이 작성합니다.
앞서 application.yml 에서 설정한 정보를 입력하는 것인데, 주석에 있듯, 보안 설정이 필요 없을 경우 // SMTP 종류별 설정 아랫 부분의 props 설정 부분의 코드를 주석처리 하시면 됩니다.
이제 JavaMailSender 빈을 사용하여 메일을 보낼 수 있는데, 이를 사용하기 쉽도록 래핑하겠습니다.
EmailSenderComponent.kt 라는 클래스 파일을 만들고,
import com.raillylinker.springboot_mvc_template.custom_objects.CustomUtil
import jakarta.mail.internet.InternetAddress
import org.springframework.beans.factory.annotation.Value
import org.springframework.core.io.ClassPathResource
import org.springframework.mail.javamail.JavaMailSender
import org.springframework.mail.javamail.MimeMessageHelper
import org.springframework.stereotype.Component
import org.springframework.web.multipart.MultipartFile
import java.io.File
// [Spring Email 유틸]
@Component
class EmailSenderComponent(
private val javaMailSender: JavaMailSender,
@Value("\${custom-config.smtp.sender-name}")
var mailSenderName: String
) {
fun sendMessageMail(
senderName: String, // 이메일에 표시될 발송자 이름 (발송 이메일 주소는 application.yml 에 저장)
receiverEmailAddressArray: Array<String>, // 수신자 이메일 배열
carbonCopyEmailAddressArray: Array<String>?, // 참조자 이메일 배열
subject: String, // 이메일 제목
message: String, // 이메일 내용
sendFileList: List<File>?, // 첨부파일 리스트
sendMultipartFileList: List<MultipartFile>? // 첨부파일 리스트 (멀티파트)
) {
val mimeMessage = javaMailSender.createMimeMessage()
val isMultipart = !sendFileList.isNullOrEmpty() || !sendMultipartFileList.isNullOrEmpty() // multipart 전송 여부
val mimeMessageHelper = MimeMessageHelper(mimeMessage, isMultipart, "UTF-8")
mimeMessageHelper.setFrom(InternetAddress(mailSenderName, senderName)) // 발송자명 적용
mimeMessageHelper.setTo(receiverEmailAddressArray) // 수신자 이메일 적용
if (carbonCopyEmailAddressArray != null) {
mimeMessageHelper.setCc(carbonCopyEmailAddressArray) // 참조자 이메일 적용
}
mimeMessageHelper.setSubject(subject) // 메일 제목 적용
mimeMessageHelper.setText(message, false) // 메일 본문 내용 적용
// 첨부파일 적용
if (sendFileList != null) {
for (sendFile in sendFileList) {
mimeMessageHelper.addAttachment(sendFile.name, sendFile)
}
}
if (sendMultipartFileList != null) {
for (sendFile in sendMultipartFileList) {
mimeMessageHelper.addAttachment(sendFile.originalFilename!!, sendFile)
}
}
javaMailSender.send(mimeMessage)
}
// (ThymeLeaf 로 랜더링 한 HTML 이메일 발송)
fun sendThymeLeafHtmlMail(
senderName: String, // 이메일에 표시될 발송자 이름 (발송 이메일 주소는 application.yml 에 저장)
receiverEmailAddressArray: Array<String>, // 수신자 이메일 배열
carbonCopyEmailAddressArray: Array<String>?, // 참조자 이메일 배열
subject: String, // 이메일 제목
thymeLeafTemplateName: String, // thymeLeaf Html 이름 (ex : resources/templates/test.html -> "test")
thymeLeafDataVariables: Map<String, Any>?, // thymeLeaf 템플릿에 제공할 정보 맵
// thymeLeaf 내에 사용할 cid 파일 리스트
/*
Map 타입 변수는 (변수명, 파일 경로)의 순서이며,
thymeLeafCidFileMap 은 ("image1", File("d://document/images/image-1.jpeg")) 이렇게,
thymeLeafCidFileClassPathResourceMap 은 ("image2", ClassPathResource("static/images/image-2.jpeg")) 이렇게 입력하고,
img 테그의 src 에는 'cid:image1' 혹은 'cid:image2' 이렇게 표시
*/
thymeLeafCidFileMap: Map<String, File>?,
thymeLeafCidFileClassPathResourceMap: Map<String, ClassPathResource>?,
sendFileList: List<File>?, // 첨부파일 리스트
sendMultipartFileList: List<MultipartFile>? // 첨부파일 리스트 (멀티파트)
) {
val mimeMessage = javaMailSender.createMimeMessage()
val mimeMessageHelper = MimeMessageHelper(mimeMessage, true, "UTF-8")
mimeMessageHelper.setFrom(InternetAddress(mailSenderName, senderName)) // 발송자명 적용
mimeMessageHelper.setTo(receiverEmailAddressArray) // 수신자 이메일 설정
if (carbonCopyEmailAddressArray != null) {
mimeMessageHelper.setCc(carbonCopyEmailAddressArray) // 참조자 이메일 설정
}
mimeMessageHelper.setSubject(subject)
// 타임리프 HTML 랜더링
val htmlString: String =
CustomUtil.parseHtmlFileToHtmlString(
thymeLeafTemplateName,
thymeLeafDataVariables ?: mapOf()
)
mimeMessageHelper.setText(htmlString, true)
// cid 파일 적용
if (thymeLeafCidFileMap != null) {
for (thymeLeafCidFileData in thymeLeafCidFileMap) {
mimeMessageHelper.addInline(thymeLeafCidFileData.key, thymeLeafCidFileData.value)
}
}
if (thymeLeafCidFileClassPathResourceMap != null) {
for (thymeLeafCidFileData in thymeLeafCidFileClassPathResourceMap) {
mimeMessageHelper.addInline(thymeLeafCidFileData.key, thymeLeafCidFileData.value)
}
}
// 첨부파일 적용
if (sendFileList != null) {
for (sendFile in sendFileList) {
mimeMessageHelper.addAttachment(sendFile.name, sendFile)
}
}
if (sendMultipartFileList != null) {
for (sendFile in sendMultipartFileList) {
mimeMessageHelper.addAttachment(sendFile.originalFilename!!, sendFile)
}
}
javaMailSender.send(mimeMessage)
}
}
위와 같이 작성하면 됩니다.
JavaMailSender 를 사용하여 텍스트 이메일을 보내거나, HTML 이메일을 보내는 함수를 구현한 것으로, 앞으로 이메일을 보낼 때는 SMTP 설정만 잘 해둔 상태에서 위 함수를 사용하기만 하면 됩니다.
- 함수 사용 예시
각 함수를 사용해보겠습니다.
일반 메일 전송 함수는 간단하게,
fun api1SendEmailTest(
httpServletResponse: HttpServletResponse,
inputVo: C6Service1TkV1TestController.Api1SendEmailTestInputVo
) {
emailSenderComponent.sendMessageMail(
inputVo.senderName,
inputVo.receiverEmailAddressList.toTypedArray(),
inputVo.carbonCopyEmailAddressList?.toTypedArray(),
inputVo.subject,
inputVo.message,
null,
inputVo.multipartFileList
)
httpServletResponse.status = HttpStatus.OK.value()
}
위와 같이 사용하여 이메일을 전송하면 되며,
HTML 이메일 전송 함수는,
fun api2SendHtmlEmailTest(
httpServletResponse: HttpServletResponse,
inputVo: C6Service1TkV1TestController.Api2SendHtmlEmailTestInputVo
) {
// CID 는 첨부파일을 보내는 것과 동일한 의미입니다.
// 고로 전송시 서버 성능에 악영향을 끼칠 가능성이 크고, CID 처리도 번거로우므로, CDN 을 사용하고, CID 는 되도록 사용하지 마세요.
emailSenderComponent.sendThymeLeafHtmlMail(
inputVo.senderName,
inputVo.receiverEmailAddressList.toTypedArray(),
inputVo.carbonCopyEmailAddressList?.toTypedArray(),
inputVo.subject,
"for_c6_n2_send_html_email_test/html_email_sample",
hashMapOf(
Pair("message", inputVo.message)
),
null,
hashMapOf(
"html_email_sample_css" to ClassPathResource("static/for_c6_n2_send_html_email_test/html_email_sample.css"),
"image_sample" to ClassPathResource("static/for_c6_n2_send_html_email_test/image_sample.jpg")
),
null,
inputVo.multipartFileList
)
httpServletResponse.status = HttpStatus.OK.value()
}
이처럼 thymeleaf HTML 경로와 thymeleaf value map, thymeleaf 첨부 파일 map 등을 넣어주면 됩니다.
공통적으로는, 발행인 이름 설정, 수신인 이메일 주소 설정, 참고인 이메일 주소 설정, 제목, 첨부파일을 설정할 수 있습니다.
- 이상입니다.
'Springboot' 카테고리의 다른 글
Springboot Redis 설정 및 사용 (다중 데이터 소스, Redis Cluster 적용) (1) | 2024.10.08 |
---|---|
Springboot 요청/응답 자동 로깅 필터 만들기 (3) | 2024.10.08 |
Springboot 에서 AWS S3 다루기 (1) | 2024.10.08 |
Springboot MongoDB 설정하기 (멀티 소스 데이터베이스 접속, MongoDB ReplicaSet 접속 및 트랜젝션 Annotation 작성) (0) | 2024.10.08 |
Springboot JPA 설정하기 (멀티 소스 데이터베이스 접속 및 트랜젝션 Annotation 작성) (2) | 2024.10.08 |