Skip to content

Commit

Permalink
refactor: AWS BCC 메일 발송 기능 리펙터링
Browse files Browse the repository at this point in the history
  • Loading branch information
MyaGya committed Oct 11, 2021
1 parent 892410f commit 0d50365
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 80 deletions.
5 changes: 4 additions & 1 deletion src/main/kotlin/apply/application/mail/MailService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package apply.application.mail
import apply.application.ApplicationProperties
import apply.application.ResetPasswordRequest
import apply.domain.user.User
import org.springframework.boot.autoconfigure.mail.MailProperties
import org.springframework.core.io.ByteArrayResource
import org.springframework.scheduling.annotation.Async
import org.springframework.stereotype.Service
Expand All @@ -13,7 +14,8 @@ import org.thymeleaf.spring5.ISpringTemplateEngine
class MailService(
private val applicationProperties: ApplicationProperties,
private val templateEngine: ISpringTemplateEngine,
private val mailSender: MailSender
private val mailSender: MailSender,
private val mailProperties: MailProperties
) {
val MAIL_SENDING_UNIT = 50

Expand Down Expand Up @@ -70,6 +72,7 @@ class MailService(

@Async
fun sendMailsByBCC(request: MailData, files: Map<String, ByteArrayResource>) {
request.recipients.plus(mailProperties.username)
for (targetMailsPart in request.recipients.chunked(MAIL_SENDING_UNIT)) {
mailSender.sendBcc(targetMailsPart.toTypedArray(), request.subject, request.body, files)
}
Expand Down
87 changes: 8 additions & 79 deletions src/main/kotlin/apply/infra/mail/AwsMailSender.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,10 @@ import com.amazonaws.services.simpleemail.model.Body
import com.amazonaws.services.simpleemail.model.Content
import com.amazonaws.services.simpleemail.model.Destination
import com.amazonaws.services.simpleemail.model.Message
import com.amazonaws.services.simpleemail.model.RawMessage
import com.amazonaws.services.simpleemail.model.SendEmailRequest
import com.amazonaws.services.simpleemail.model.SendRawEmailRequest
import org.springframework.boot.autoconfigure.mail.MailProperties
import org.springframework.core.io.ByteArrayResource
import org.springframework.stereotype.Component
import java.io.ByteArrayOutputStream
import java.nio.ByteBuffer
import java.util.Properties
import javax.activation.DataHandler
import javax.activation.DataSource
import javax.activation.MimetypesFileTypeMap
import javax.mail.Session
import javax.mail.internet.InternetAddress
import javax.mail.internet.MimeBodyPart
import javax.mail.internet.MimeMessage
import javax.mail.internet.MimeMultipart
import javax.mail.util.ByteArrayDataSource
import javax.mail.Message as javaxMessage

@Component
Expand Down Expand Up @@ -66,77 +52,20 @@ class AwsMailSender(
body: String,
files: Map<String, ByteArrayResource>
) {
val multipartMimeMessage = message {
this.subject = subject
this.userName = mailProperties.username
this.recipient = Recipient(javaxMessage.RecipientType.BCC, toAddresses)
this.body = body
this.files = files
}.build()

var message: MimeMessage? = null
val session = Session.getDefaultInstance(Properties())
// Create a new MimeMessage object.
message = MimeMessage(session)
// Add subject, from and to lines.
message.setSubject(subject, "UTF-8")
message.setFrom(InternetAddress(mailProperties.username)) // SENDER, [email protected]
message.setRecipients(javaxMessage.RecipientType.TO, toAddresses.map { InternetAddress(it) }.toTypedArray())
// Create a multipart/alternative child container.
val msgBody = MimeMultipart("alternative")
val wrap = MimeBodyPart()
val textPart = MimeBodyPart()
textPart.setContent(body, "text/plain; charset=UTF-8")

// val htmlPart = MimeBodyPart()
// htmlPart.setContent(bodyHTML, "text/html; charset=UTF-8") // BODY HTML 은 제외, 제외해도 돌아가는가?
// msgBody.addBodyPart(htmlPart)
msgBody.addBodyPart(textPart)
wrap.setContent(msgBody)
// Create a multipart/mixed parent container.
val msg = MimeMultipart("mixed")
// Add the parent container to the message.
message.setContent(msg)
// Add the multipart/alternative part to the message.
msg.addBodyPart(wrap)
// Define the attachment

// val fds: DataSource = ByteArrayDataSource(attachment, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") <- 레퍼런스
for ((fileName, fileData) in files) {
val att = MimeBodyPart()
val fds: DataSource = ByteArrayDataSource(
fileData.byteArray,
MimetypesFileTypeMap().getContentType(fileName)
)
// val fds: DataSource = FileDataSource("C:\\Users\\kirin\\Desktop\\의문점 1.png")

att.dataHandler = DataHandler(fds)
att.fileName = fileName
// val reportName = "PhotoReport.xls" <- 이 항목이 있는걸로 보아 att.fileName으로 이름을 붙여줄 수 있는듯
// att.fileName = reportName
msg.addBodyPart(att)
}

// Add the attachment to the message.

// Try to send the email.
val rawEmailRequest = multipartMimeMessage.getRawEmailRequest()
try {
// println("Attempting to send an email through Amazon SES " + "using the AWS SDK for Java...")
// Print the raw email content on the console
// Print the raw email content on the console
val out = System.out
message.writeTo(out)
// Send the email.
// Send the email.
val outputStream = ByteArrayOutputStream()
message.writeTo(outputStream)
val rawMessage = RawMessage(ByteBuffer.wrap(outputStream.toByteArray()))

val rawEmailRequest = SendRawEmailRequest(rawMessage)
// .withConfigurationSetName("ConfigSet") // <- 기본값

client.sendRawEmail(rawEmailRequest)
// println("Email sent!")
// Display an error if something goes wrong.
} catch (ex: Exception) {
println("Email Failed")
println("Error message: ${ex.message}}")
ex.printStackTrace()
}
println("Email sent with attachment")
}

private fun createContent(data: String): Content {
Expand Down
100 changes: 100 additions & 0 deletions src/main/kotlin/apply/infra/mail/MultipartMimeMessage.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package apply.infra.mail

import com.amazonaws.services.simpleemail.model.RawMessage
import com.amazonaws.services.simpleemail.model.SendRawEmailRequest
import org.springframework.core.io.ByteArrayResource
import java.io.ByteArrayOutputStream
import java.nio.ByteBuffer
import java.util.Properties
import javax.activation.DataHandler
import javax.activation.DataSource
import javax.activation.MimetypesFileTypeMap
import javax.mail.Message
import javax.mail.Session
import javax.mail.internet.InternetAddress
import javax.mail.internet.MimeBodyPart
import javax.mail.internet.MimeMessage
import javax.mail.internet.MimeMultipart
import javax.mail.util.ByteArrayDataSource

data class Recipient(val recipientType: Message.RecipientType, val toAddresses: Array<String>)

class MultipartMimeMessage(session: Session, private val mimeMixedPart: MimeMultipart) {
val message: MimeMessage = MimeMessage(session)

fun setSubject(subject: String) {
message.setSubject(subject, "UTF-8")
}

fun setFrom(userName: String) {
message.setFrom(InternetAddress(userName))
}

fun setRecipient(recipient: Recipient) {
message.setRecipients(recipient.recipientType, recipient.toAddresses.map { InternetAddress(it) }.toTypedArray())
}

fun addBody(body: String) {
val messageBody = MimeMultipart("alternative")
val wrap = MimeBodyPart()
val textPart = MimeBodyPart()
textPart.setContent(body, "text/plain; charset=UTF-8")
messageBody.addBodyPart(textPart)
wrap.setContent(messageBody)
message.setContent(mimeMixedPart)
mimeMixedPart.addBodyPart(wrap)
}

fun addAttachment(files: Map<String, ByteArrayResource>) {
for ((fileName, fileData) in files) {
val att = MimeBodyPart()
val fds: DataSource = ByteArrayDataSource(
fileData.byteArray,
findMimeContentTypeByFileName(fileName)
)
att.dataHandler = DataHandler(fds)
att.fileName = fileName
mimeMixedPart.addBodyPart(att)
}
}

private fun findMimeContentTypeByFileName(fileName: String): String {
return MimetypesFileTypeMap().getContentType(fileName)
?: throw IllegalArgumentException("잘못된 확장자입니다.")
}

fun getRawEmailRequest(): SendRawEmailRequest {
val rawMessage = createRawMessage(message)
return SendRawEmailRequest(rawMessage)
}

private fun createRawMessage(message: MimeMessage): RawMessage {
val outputStream = ByteArrayOutputStream()
message.writeTo(outputStream)
return RawMessage(ByteBuffer.wrap(outputStream.toByteArray()))
}
}

data class MultipartMimeMessageBuilder(
var session: Session = Session.getDefaultInstance(Properties()),
var mimeMixedPart: MimeMultipart = MimeMultipart("mixed"),
var subject: String = "",
var userName: String = "",
var recipient: Recipient? = null,
var body: String = "",
var files: Map<String, ByteArrayResource>? = null
) {
fun build(): MultipartMimeMessage {
return MultipartMimeMessage(session, mimeMixedPart).apply {
setSubject(subject)
setFrom(userName)
setRecipient(recipient!!)
addBody(body)
addAttachment(files!!)
}
}
}

fun message(lambda: MultipartMimeMessageBuilder.() -> Unit): MultipartMimeMessageBuilder {
return MultipartMimeMessageBuilder().apply(lambda)
}

0 comments on commit 0d50365

Please sign in to comment.