Springboot 으로 email 전송기능을 구현 하는 방법에는 다양하게 존재한다고 한다.
오늘은 내가 알고 있는 방법으로 글을 써볼까한다.
쓰레드 환경에서도 많은 사람한테 보낼수 있는 기능이라고 가져다가 자기 환경에 맞게 조금 수정하면 잘 써질듯하다.
controller 에서 responseEntity 하는 부분은 대충 써놔서 수정이 조금 필요한듯 싶다.
그럼 코드 go.go.go
pom.xml 에 추가
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
application.yml 파일 작성
server:
port: 8080
spring:
mail:
host: smtp.gmail.com
username: your_google_account@gmail.com
password: mxmiujqrxzgfabcd
default-encoding: UTF-8
properties:
mail:
smtp:
auth: false
starttls:
enable: true
required: true
멀티스레드 풀 관련 config 작성
@EnableAsync
@Configuration
public class ExecutorConfig extends AsyncConfigurerSupport {
/**
* 스레드풀 사이즈 설정
**/
private int corePoolSize = 4;
/**
* 스레드풀 초대 사이즈 설정
**/
private int maxPoolSize = 16;
/**
* 스레드풀 큐 사이즈
**/
private int queueCapacity = 10;
/**
* 스레드 이름 접두사
*/
private String threadNamePrefix = "EmailAsyncExecutor-";
@Bean("EmailAsync")
public ThreadPoolTaskExecutor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix(threadNamePrefix);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return executor;
}
}
Email 객체 생성
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Builder
public class EmailModel implements Serializable {
/**
* 초기화
*/
private static final long serialVersionUID = 1404185636399251685L;
/**
* 수신자
*/
private String email;
/**
* 메일 제목
*/
private String subject;
/**
* 메일 내용
*/
private String content;
/**
* 첨부파일 위치
*/
private String attachFilePath;
/**
* 메일 resource 위치
*/
private String resourcePath;
/**
* 메일 resource 이름
*/
private String resourceName;
}
Email Service 작성
package com.example.demo.service.impl;
import com.example.demo.model.EmailModel;
import com.example.demo.service.MailService;
import lombok.RequiredArgsConstructor;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
@Service
@RequiredArgsConstructor
public class MailServiceImpl implements MailService {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(MailServiceImpl.class);
private final JavaMailSender mailSender;
@Value("${spring.mail.username}")
private String from;
@Async("EmailAsync")
@Override
public Boolean sendSimpleMail(EmailModel emailModel) {
try {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(from);// 보내는 사람, 설정 하지 않으면 기본 값 .properties 값이 셋팅된다.
message.setTo(emailModel.getEmail().split(";"));//수신자 1명 혹은 여러명일때 ";" 로 분리
message.setSubject(emailModel.getSubject());// 제목
message.setText(emailModel.getContent());// 본문
mailSender.send(message);
logger.info("단순 문자전자 메일전송 성공!");
} catch (Exception e) {
e.printStackTrace();
logger.error("단순 문자전자 메일전송 실패!");
return false;
}
return true;
}
@Async("EmailAsync")
@Override
public Boolean sendHtmlMail(EmailModel emailModel) {
String to = emailModel.getEmail();
String subject = emailModel.getSubject();
String content = emailModel.getContent();
logger.info("HTML Template 메일전송 시작:{},{},{}", to, subject, content);
//MimeMessage,MIME 프로토콜 사용
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper;
//MimeMessageHelper 더욱 많은 내용들을 설정 할수 있다.
try {
helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to.split(";"));
helper.setSubject(subject);
helper.setText(content, true);// ture 일시 html 지원
mailSender.send(message);
logger.info("HTML Template 메일전송 성공!");
} catch (MessagingException e) {
logger.error("HTML Template 메일전송 실패!", e);
return false;
}
return true;
}
@Async("EmailAsync")
@Override
public Boolean sendAttachmentMail(EmailModel emailModel) {
String to = emailModel.getEmail();
String subject = emailModel.getSubject();
String content = emailModel.getContent();
String filePath = emailModel.getAttachFilePath();
logger.info("첨부파일 메일전송 시작:{},{},{},{}", to, subject, content, filePath);
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper;
try {
helper = new MimeMessageHelper(message, true); //true 파일 여러개라는 뜻
helper.setFrom(from);
helper.setTo(to.split(";"));
helper.setSubject(subject);
helper.setText(content, true);
FileSystemResource file = new FileSystemResource(new File(filePath));
String fileName = file.getFilename();
helper.addAttachment(fileName, file);//添加附件,可多次调用该方法添加多个附件
mailSender.send(message);
logger.info("첨부파일 메일전송 성공!");
} catch (MessagingException e) {
logger.error("첨부파일 메일전송 실패!", e);
return false;
}
return true;
}
@Async("EmailAsync")
@Override
public Boolean sendInlineResourceMail(EmailModel emailModel) {
String to = emailModel.getEmail();
String subject = emailModel.getSubject();
String content = emailModel.getContent();
String resourcePath = emailModel.getResourcePath();
String resourceName = emailModel.getResourceName();
logger.info("첨부파일 메일전송 시작:{},{},{},{},{}", to, subject, content, resourcePath, resourceName);
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper;
try {
helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to.split(";"));
helper.setSubject(subject);
helper.setText(content, true);
// 절대경로를 읽는다
FileSystemResource res = new FileSystemResource(new File(resourcePath));
helper.addInline(resourceName, res);//파일여러개 일때 여러번 사용가능
mailSender.send(message);
logger.info("첨부파일 메일전송 성공!");
} catch (MessagingException e) {
logger.error("첨부파일 메일전송 실패!", e);
return false;
}
return true;
}
@Async("EmailAsync")
@Override
public Boolean sendHtmlImageMail(EmailModel emailModel) {
String to = emailModel.getEmail();
String subject = emailModel.getSubject();
String content = emailModel.getContent();
String resourcePath = emailModel.getResourcePath();
logger.info("첨부파일 메일전송 시작:{},{},{},{}", to, subject, content, resourcePath);
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper;
try {
helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to.split(";"));
helper.setSubject(subject);
helper.setText(content, true);
helper.setText("<html><head></head><body><h1>hello world!</h1>" + "<img src=\"cid:aaa\"/></body></html>", true);
FileSystemResource img = new FileSystemResource(new File(resourcePath));
helper.addInline("aaa", img);
mailSender.send(message);
logger.info("첨부파일 메일전송 성공!");
return true;
} catch (MessagingException e) {
logger.error("첨부파일 메일전송 실패!", e);
return false;
}
}
}
서비스를 호출할 Controller 작성
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/mail")
public class MailController {
private final MailService mailService;
@PostMapping("/test")
public ResponseEntity sendSimpleMail(String toEmail) {
mailService.sendSimpleMail(EmailModel
.builder()
.email(toEmail)
.subject("test")
.content("일단 아무거나 테스트")
.build());
return ResponseEntity.ok().build();
}
@PostMapping("/simple")
public ResponseEntity sendSimpleMail(@RequestBody EmailModel emailModel) {
mailService.sendSimpleMail(emailModel);
return ResponseEntity.ok().build();
}
@PostMapping("/html")
public ResponseEntity sendHtmlMail(@RequestBody EmailModel emailModel) {
mailService.sendHtmlMail(emailModel);
return ResponseEntity.ok().build();
}
@PostMapping("/attach")
public ResponseEntity sendAttachmentMail(@RequestBody EmailModel emailModel) {
mailService.sendAttachmentMail(emailModel);
return ResponseEntity.ok().build();
}
@PostMapping("/resource")
public ResponseEntity sendInlineResourceMail(@RequestBody EmailModel emailModel) {
mailService.sendInlineResourceMail(emailModel);
return ResponseEntity.ok().build();
}
@PostMapping("/image")
public ResponseEntity sendHtmlImageMail(@RequestBody EmailModel emailModel) {
mailService.sendHtmlImageMail(emailModel);
return ResponseEntity.ok().build();
}
}
POSTMAN 으로 이메일 테스트 해볼게
네이버에서 메일에서 확인
트러블슈팅
아래와 같이 에러가 나온다.
구글 보안 문제로 구글패스워드 아닌 앱 키를 발급받아서 적용해야 된다. 다른 편번으로 임시로 테스트하는 방법도 있지만 보안문제로 그냥 이대로 쓰는거 편하다.
setp1:
setp2:
mxmiujqrxzgfabcd
이런 유형의 문자열을 복사해서 yml 파일 설정 항목중 password 해당부분에 넣으면 된다.
게으른 당신을 위한 소스코드 https://github.com/luxury515/luxury515-springboot-email-thread
이상끝!