개발환경
프로젝트 생성
의존성 추가
기본 설정 및 구글 SMTP 변수 설정
application.yml 설정
구글 메일 발송 구현
DTO 추가
AsyncConfig 구현
service 구현
컨트롤러, 프론트 페이지 추가
컨트롤러 생성
메인 페이지 생성
메일 템플릿
참고한 사이트
프로젝트 구조
GitHub 링크
실행화면
개발 환경 | 버전 |
---|---|
Java | 17 |
Spring Boot | 3.2.8 |
Spring Boot Starter Mail | 3.2.8 |
Lombok | 1.18.30 |
빌드 관리 도구 | Gradle 8.8 |
템플릿 엔진 | Mustache |
개발 도구 | Spring Tool Suite 4.22.1 |
Spring Boot Version 3.2.8 선택합니다.
검색란에 의존성 키워드를 입력하여 의존성을 추가합니다. (녹색 영역 참조)
Mustache 템플릿 compile에 필요한 라이브러리
URL : https://mvnrepository.com/artifact/com.github.spullara.mustache.java/compiler
Gradle (Short) : implementation 'com.github.spullara.mustache.java:compiler:0.9.14'
application.properties파일의 확장자를 application.yml 확장자로 변경합니다.
username : 앱 비밀번호 생성한 구글 아이디 ex) test@gamil.com
password : 앱 비밀번호
spring:
application:
name: email
#mustache UTF-8
server:
servlet:
encoding:
force: true
---
#mustache 설정
spring:
mustache:
cache: false
servlet:
expose-request-attributes: true #mustache에서 csrf 토큰 변수 오류 발생 때문에 추가
expose-session-attributes: true #세션
---
#메일 발송
spring:
mail:
host: smtp.gmail.com
port: 587
username: [앱 비밀번호 생성한 구글 아이디] #test@gmail.com
password: zrhq ceee dzdm mjlx #앱 비밀번호
properties:
mail:
smtp:
auth: true
timeout: 5000
starttls:
enable: true
dto 패키지를 생성 후 MailDto 클래스 파일을 생성합니다.
패키지 위치 : com.example.email.dto
package com.example.email.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class MailDto {
private String title; // 제목
private String contents; // 내용
private String company; // 상호명
private String name; // 받는 사람 이름
private String email; // 상호명
private String link; // 버튼 링크
}
ResultDto 클래스 파일을 생성합니다.
패키지 위치 : com.example.email.dto
package com.example.email.dto;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
public class ResultDto {
private String resultCode = "ERROR";
private String message = "오류가 발생하였습니다.";
@Builder
public ResultDto (String resultCode, String message, Object resultData, String url) {
this.resultCode = resultCode;
this.message = message;
}
}
config 패키지를 생성 후 AsyncConfig 클래스 파일을 생성합니다.
패키지 위치 : com.example.email.config
Thread 설정 값은 프로젝트 환경에 따라 다를 수 있습니다.
package com.example.email.config;
import java.util.concurrent.Executor;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@EnableAsync
@Configuration
public class AsyncConfig implements AsyncConfigurer {
@Bean
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2); // 실행 대기 중인 최소 Thread의 개수
executor.setMaxPoolSize(5); // 동시에 동작하는 최대 Thread의 개수
executor.setQueueCapacity(10); // 큐의 최대 용량 (CorePool의 크기를 넘어서면 큐에 저장함)
executor.setThreadNamePrefix("Async MailExecutor");
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return AsyncConfigurer.super.getAsyncUncaughtExceptionHandler();
}
}
service 패키지를 생성 후 MailService 클래스 파일을 생성합니다.
패키지 위치 : com.example.email.service
import 에러 발생 시 "Refresh Gradle Project" 실행 해주세요.
package com.example.email.service;
import java.io.StringWriter;
import java.util.Map;
import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.RequiredArgsConstructor;
import com.example.email.dto.MailDto;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
@RequiredArgsConstructor
@Service
public class MailService {
private final JavaMailSender javaMailSender;
@Async
public void sendMail(MailDto mailDto, Map<String, String> userInfo) throws MessagingException {
try {
// 메일에 들어갈 값 설정
MailDto sendMailDto = new MailDto();
sendMailDto.setCompany("DevDream"); // 상호명
sendMailDto.setLink("https://devdream.net"); // 버튼 링크
sendMailDto.setTitle(mailDto.getTitle()); // 제목
sendMailDto.setContents(mailDto.getContents().replaceAll("\n", "<br>")); // 내용, 개행문자 치환
sendMailDto.setName(userInfo.get("name").toString()); // 받는 사람 이름
sendMailDto.setEmail(userInfo.get("email").toString()); // 받는 사람 이메일
MustacheFactory mf = new DefaultMustacheFactory();
Mustache m = mf.compile("templates/mail_form.mustache"); // mail form (template)
StringWriter sw = new StringWriter();
m.execute(sw, sendMailDto);
sw.flush();
String mailContents = sw.toString();
MimeMessagePreparator preparator = new MimeMessagePreparator() {
@Override
public void prepare(MimeMessage mimeMessage) throws Exception {
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
// 받는 사람 이메일
helper.setTo(sendMailDto.getEmail());
// 제목
helper.setSubject(sendMailDto.getTitle());
// 내용
helper.setText(mailContents, true);
}
};
// 메일 발송
this.javaMailSender.send(preparator);
} catch (MailException e) {
System.out.println(e.getMessage());
}
}
}
controller 패키지를 생성 후 MainController 클래스 파일을 생성합니다.
패키지 위치 : com.example.email.controller
이메일 발송 대상자를 DB 조회 하여 userList 리스트에 넣으면 됩니다.
package com.example.email.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import com.example.email.dto.MailDto;
import com.example.email.dto.ResultDto;
import com.example.email.service.MailService;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Controller
public class MainController {
private final MailService mailService;
/**
* 메인 페이지
* @return
*/
@GetMapping("/")
public String getMethodName() {
return "index";
}
/**
* 메일 발송
* @param mailDto
* @return
*/
@PostMapping(value = "/send_mail", produces = "application/json; charset=utf8")
public ResponseEntity<ResultDto> sendMail(@RequestBody MailDto mailDto) {
ResultDto result = new ResultDto();
try {
// 메일 발송 대상자
List<Map<String, String>> userList = new ArrayList<Map<String, String>>();
Map<String, String> map = new HashMap<String, String>();
map.put("name", "김철수");
map.put("email", "test@nate.com");
userList.add(map);
map = new HashMap<String, String>();
map.put("name", "장철수");
map.put("email", "test@gmail.com");
userList.add(map);
map = new HashMap<String, String>();
map.put("name", "이영희");
map.put("email", "test@gmail.com");
userList.add(map);
map = new HashMap<String, String>();
map.put("name", "홍길동");
map.put("email", "test@daum.net");
userList.add(map);
for (int i = 0; i < userList.size(); i++) {
mailService.sendMail(mailDto, userList.get(i));
}
result = ResultDto.builder()
.resultCode("SUCCESS")
.message("발송이 완료되었습니다.")
.build();
} catch (Exception e) {
System.out.println(e.getMessage());
}
return new ResponseEntity<ResultDto>(result, HttpStatus.OK);
}
}
파일 다운로드 : index.mustache
index.mustache 파일 다운로드 후 templates에 넣어줍니다.
파일 다운로드 : mail_form.mustache
mail_form.mustache 파일 다운로드 후 templates에 넣어줍니다.
메일 템플릿 출처 : https://www.bootdey.com/snippets/tagged/email
2) https://www.baeldung.com/mustache
google smtp | |
---|---|
2024.07.27 | 구글 SMTP를 활용한 Mustache 템플릿 메일 보내기 (2) |
2024.07.25 | 구글 SMTP를 활용한 Mustache 템플릿 메일 보내기 (1) |