1. 개인화된 공간: 각 사용자마다 고유한 메일 박스가 할당됩니다. 2. 메시지 저장: 받은 이메일, 보낸 이메일, 임시 저장 메일 등을 보관합니다. 3. 폴더 구조: 사용자가 메일을 체계적으로 정리할 수 있도록 폴더 시스템을 제공합니다. 4. 용량 제한: 일반적으로 메일 서비스 제공자가 정한 저장 용량 제한이 있습니다. 5. 접근 방식: IMAP이나 POP3 프로토콜을 통해 접근 가능합니다.
3. Spring Boot Mail 클래스 구조
💡 Spring Boot Mail 클래스 구조
- Spring Boot Mail 라이브러리를 사용하는 경우에 사용되는 클래스/인터페이스 구조에 대해 알아봅니다.
클래스 / 인터페이스
분류
설명
MailMessage
인터페이스
이메일 메시지의 기본 인터페이스로, 메시지의 기본 속성을 정의합니다.
SimpleMailMessage
인터페이스 구현체(클래스)
간단한 텍스트 이메일을 위한 구현체로, 기본적인 이메일 속성만을 포함합니다.
MimeMessage
인터페이스 구현체(클래스)
복잡한 이메일(HTML, 첨부파일 등)을 위한 구현체로, 다양한 MIME 타입을 지원합니다.
MailSender
인터페이스
이메일 전송을 위한 기본 인터페이스로, SimpleMailMessage 전송 메서드를 제공합니다.
JavaMailSender
인터페이스
MailSender를 확장한 인터페이스로, MimeMessage 및 첨부파일 지원 등 추가 기능을 제공합니다.
JavaMailSenderImpl
인터페이스 구현체(클래스)
JavaMailSender 인터페이스의 실제 구현체로, SMTP 서버 설정 및 이메일 전송 로직을 포함합니다.
- MimeMessage를 좀 더 쉽게 사용할 수 있도록 해주는 래퍼 클래스입니다. 이를 통해 복잡한 이메일 구성을 간단하게 만들어줍니다.
💡 사용 예시
- MimeMessage 직접 사용하는 경우와 MimeMessageHelper를 사용하는 경우가 있습니다.
- MimeMessage의 경우는 직접 사용하면 세부적인 제어가 가능하지만, 복잡한 API를 다뤄야 합니다. - MimeMessageHelper의 경우는 MimeMessage 생성을 간소화하고, 편리한 메서드를 제공합니다. 이를 통해 복잡한 이메일 구성을 간단하게 만들어줍니다.
// MimeMessage 직접 사용
MimeMessage message = mailSender.createMimeMessage();
message.setSubject("제목");
message.setText("내용");
message.setRecipients(Message.RecipientType.TO, "recipient@example.com");
// MimeMessageHelper 사용
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setSubject("제목");
helper.setText("내용", true); // HTML 지원
helper.setTo("recipient@example.com");
helper.addAttachment("파일명.pdf", new File("경로/파일명.pdf"));
2) Spirng Boot Mail 공통 기본 설정
1. 개발 환경
개발 환경
버전
java
17
Spring Boot
3.3.5
spring-boot-starter-web
3.3.5
spring-boot-starter-mail
3.3.5
lombok
-
SMTP
Google, Naver
2. 의존성 추가
💡 의존성 추가
- API 호출로 데이터를 받아서 메일을 전송하는 구조로 구성하였습니다. 또한 html 이메일 전송을 위해 thymeleaf 의존성을 추가하였습니다.
spring:
mail:
host: smtp.gmail.com # 구글 SMTP 서버 주소
port: 587 # 구글 SMTP 포트 번호
username: xxxxxxxx@gmail.com # 사용자 이메일
password: xxxx xxxx xxxx xxxx # 사용자 앱 비밀번호
properties:
mail:
smtp:
auth: true # 사용자 인증 여부
timeout: 5000 # 이메일 전송 타임아웃 시간
starttls:
enable: true # TLS를 통해 안전한 통신 사용 여부
3) Spirng Boot Mail 활용하기 -1 : 텍스트 기반 메일 전송
💡 Spirng Boot Mail 활용하기 -1 : 텍스트 기반 메일 전송
- 해당 구성에서는 API 호출로 데이터가 전달이 되었을 때, 텍스트 기반의 메일을 전송하도록 구성하였습니다.
1. MailTxtSendDto
💡 MailTxtSendDto
- 간단한 구조로 수신자 이메일, 이메일 제목, 이메일 내용 형태로 객체를 클라이언트로부터 전달받는 구조로 구성하였습니다.
- 이메일 전송에 대한 반환값을 받을 수는 없기에 MailTxtSendDto 객체를 파라미터로 전달하여 비즈니스 로직을 처리하도록 하는 인터페이스를 구성하였습니다.
package com.adjh.springbootmail.service;
import com.adjh.springbootmail.dto.MailTxtSendDto;
import org.springframework.stereotype.Service;
/**
* 이메일 전송 서비스
*
* @author : jonghoon
* @fileName : MailSendService
* @since : 11/11/24
*/
@Service
public interface MailSendService {
void sendTxtEmail(MailTxtSendDto mailTxtSendDto); // SimpleMailMessage를 활용하여 텍스트 기반 메일을 전송합니다.
}
3. MailSendServiceImpl
💡 MailSendServiceImpl
- 이메일 전송에 대한 인터페이스의 구현체로 JavaMailSender를 주입받아서 메일을 전송하는 구조입니다. - SimpleMailMessage 객체를 통해서, 받는 사람 이메일, 제목, 내용을 구성하여 JavaMailSender를 통해서 텍스트 기반 이메일을 전송하는 구조입니다.
package com.adjh.springbootmail.service.impl;
import com.adjh.springbootmail.dto.MailTxtSendDto;
import com.adjh.springbootmail.service.MailSendService;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
/**
* 이메일 전송 서비스의 구현체
*
* @author : jonghoon
* @fileName : MailSendServiceImpl
* @since : 11/11/24
*/
@Service
public class MailSendServiceImpl implements MailSendService {
private final JavaMailSender mailSender;
public MailSendServiceImpl(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
/**
* 텍스트 기반 메일 전송
*
* @param mailTxtSendDto
*/
@Override
public void sendTxtEmail(MailTxtSendDto mailTxtSendDto) {
SimpleMailMessage smm = new SimpleMailMessage();
smm.setTo(mailTxtSendDto.getEmailAddr()); // 받는 사람 이메일
smm.setSubject(mailTxtSendDto.getSubject()); // 이메일 제목
smm.setText(mailTxtSendDto.getContent()); // 이메일 내용
try {
mailSender.send(smm); // 메일 보내기
System.out.println("이메일 전송 성공!");
} catch (MailException e) {
System.out.println("[-] 이메일 전송중에 오류가 발생하였습니다 " + e.getMessage());
throw e;
}
}
}
4. 결과 확인
💡 결과 확인
- Controller 부분은 제외하였지만, 해당 서비스를 호출하여 데이터를 전달하는 구조로 되어 있습니다. - @requestBody로 아래와 같은 객체 형태로 데이터를 전달하면 이메일이 전송됩니다.
4) Spirng Boot Mail 활용하기 -2 : HTML 기반 메일 전송
💡 Spirng Boot Mail 활용하기 -2 : HTML 기반 메일 전송
- 텍스트 자체로 메일을 보내는 경우도 있지만, 일정 틀을 갖추고 디자인이 적용된 이메일을 전송하고자 할 때 이를 이용합니다.
1. MailHtmlSendDto
💡 MailHtmlSendDto
- 이전에 구성한 텍스트 메일과 동일한 구조에서 target 멤버 변수를 추가하여 각기 다른 메시지를 출력하도록 하는 동적 메일을 전송하기 위해 추가하였습니다.
package com.adjh.springbootmail.dto;
import lombok.Getter;
/**
* MimeMessageHelper 기반의 HTML 메일 전송
*
* @author : jonghoon
* @fileName : MailHtmlSendDto
* @since : 11/11/24
*/
@Getter
public class MailHtmlSendDto {
private String emailAddr; // 수신자 이메일
private String subject; // 이메일 제목
private String content; // 이메일 내용
private String target; // 이메일 대상 타겟을 지정합니다.
public MailHtmlSendDto(String emailAddr, String subject, String content, String target) {
this.emailAddr = emailAddr;
this.subject = subject;
this.content = content;
this.target = target;
}
}
2. MailSendService
💡 MailSendService
- sendHtmlEmail()에서도 동일하게 이메일 전송에 대한 반환값을 받을 수는 없기에 mailHtmlSendDto 객체를 파라미터로 전달하여 비즈니스 로직을 처리하도록 하는 인터페이스를 구성하였습니다.
package com.adjh.springbootmail.service;
import com.adjh.springbootmail.dto.MailHtmlSendDto;
import com.adjh.springbootmail.dto.MailTxtSendDto;
import org.springframework.stereotype.Service;
/**
* 이메일 전송 서비스
*
* @author : jonghoon
* @fileName : MailSendService
* @since : 11/11/24
*/
@Service
public interface MailSendService {
void sendHtmlEmail(MailHtmlSendDto mailHtmlSendDto); // MimeMessageHelper를 활용하여 HTML 기반 메일을 전송합니다.
}
- 추가로 Thymeleaf로 구성한 html 파일 자체를 메일로 전송하기 위해 TemplateEngine을 주입받았습니다. - sendHtmlEmail() 메서드에서는 MimeMessageHelper 클래스를 통해서 간단한 HTML 메시지를 구성합니다.
- Thymeleaf 템플릿 엔진을 사용하여 동적 HTML 콘텐츠를 생성합니다. 1. subject : 전달받은 객체로 메일 제목을 설정합니다. 2. message : 전달받은 객체로 메일 내용을 설정합니다. 3. userType : 전달받은 객체 중 “target”이라는 값에 따라서 유동적으로 텍스트를 출력하도록 구성하였습니다. 4. ogoImage : 프로젝트 static/images/logo.png에 있는 파일을 불러와서 base64로 변환하였습니다.
- 최종적으로 mailSender를 통해서 메일을 전송합니다.
package com.adjh.springbootmail.service.impl;
import com.adjh.springbootmail.dto.MailHtmlSendDto;
import com.adjh.springbootmail.dto.MailTxtSendDto;
import com.adjh.springbootmail.service.MailSendService;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import java.io.IOException;
import java.util.Base64;
/**
* 이메일 전송 서비스의 구현체
*
* @author : jonghoon
* @fileName : MailSendServiceImpl
* @since : 11/11/24
*/
@Service
public class MailSendServiceImpl implements MailSendService {
private final JavaMailSender mailSender;
private final TemplateEngine templateEngine;
public MailSendServiceImpl(JavaMailSender mailSender, TemplateEngine templateEngine) {
this.mailSender = mailSender;
this.templateEngine = templateEngine;
}
/**
* html 기반 메일 전송
*
* @param mailHtmlSendDto
*/
@Override
public void sendHtmlEmail(MailHtmlSendDto mailHtmlSendDto) {
try {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
Context context = new Context();
context.setVariable("subject", mailHtmlSendDto.getSubject());
context.setVariable("message", mailHtmlSendDto.getContent());
if (mailHtmlSendDto.getTarget().equals("user")) {
context.setVariable("userType", "일반 사용자");
} else if (mailHtmlSendDto.getTarget().equals("admin")) {
context.setVariable("userType", "관리자");
}
// MailSendServiceImpl.java 내부
String base64Image = getBase64EncodedImage("static/images/logo.png");
context.setVariable("logoImage", base64Image);
String htmlContent = templateEngine.process("email-template", context);
helper.setTo(mailHtmlSendDto.getEmailAddr());
helper.setSubject(mailHtmlSendDto.getSubject());
helper.setText(htmlContent, true);
mailSender.send(message);
System.out.println("Thymeleaf 템플릿 이메일 전송 성공!");
} catch (MessagingException e) {
System.out.println("[-] Thymeleaf 템플릿 이메일 전송 중 오류 발생: " + e.getMessage());
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// 이미지를 Base64로 인코딩하는 메서드
private String getBase64EncodedImage(String imagePath) throws IOException {
Resource resource = new ClassPathResource(imagePath);
byte[] bytes = StreamUtils.copyToByteArray(resource.getInputStream());
return Base64.getEncoder().encodeToString(bytes);
}
}
4. email-template.html
💡 email-template.html
- themelaf는 기본적인 설정을 하지 않는다면, resources/templates를 기본 경로로 인식을 하기에, 기본 경로에 email-template.html이라는 파일을 구성하였습니다. - static/images 경로에 logo.png 파일을 추가하여 프로젝트 내의 이미지를 메일에 포함하도록 구성하였습니다.
💡 비즈니스 로직에서 Context로 지정한 속성 값에 따라서 해당 themelaf의 html의 변수 값이 지정이 됩니다.
- 추가로 logoImage 변수는 base64로 변환된 상태이기에 그 자체로 출력을 합니다.