진행 중인 프로젝트에서 사용자에게 "임시 비밀번호 발급 및 이메일 인증 서비스"를 구현해야 했기 때문에
Spring Boot를 이용하여 메일을 전송하는 기능을 공부해보려 메일 전송 테스트를 해봤다.
환경
⚙ jdk 11
⚙ spring boot 2.7.13
⚙ Intellij
준비사항
✔ 메일을 보내기 위해선 아래 두가지 설정이 필요하다.
✅ pop3 : 메시지를 여러 장치에서 읽음으로 표시하는 기능
✅ SMTP(Simple Mail Transfer Protocol) : 전자 메일 전송을 위한 표준 프로토콜
나는 보내는 메일 주소를 gmail로 하였기 때문에 gmail에서 두가지 설정을 해주었다.
✔ 다음으로, 스프링 부트를 이용하여 메일을 보내기 위해선 Spring Boot Starter Mail 의존성이 필요하다.
✔ 이외에 application.yml에서 메일 관련 세팅을 해줘야 하는데, 초기 환경 세팅 및 코드 참조는 아래 블로그에서 참고했다.
참고한 블로그에서는 임시 비밀번호와 이메일 인증 번호를 전송하는 기능을 구현하였지만,
나는 간단하게 메일 전송 기능만 구현해보고 싶어서 해당 부분은 다 쳐내고 따로 "test" 문구만 전송하여 메일이 잘 전송되는지 확인했다.
코드
EmailMessage.java
package com.test.mailtest.domain.email.domain;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class EmailMessage {
private String userName;
private String domainAdress;
private String subject;
private String message;
}
EmailServiceImpl.java
package com.test.mailtest.domain.email.service;
import com.test.mailtest.domain.email.domain.EmailMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
@Service
@Slf4j
@RequiredArgsConstructor
public class EmailServiceImpl implements EmailService{
private final JavaMailSender javaMailSender;
public boolean sendMail(EmailMessage emailMessage) {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
try {
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, false, "UTF-8");
StringBuilder sb = new StringBuilder();
sb.append(emailMessage.getUserName()).append("@").append(emailMessage.getDomainAdress());
mimeMessageHelper.setTo(sb.toString());
mimeMessageHelper.setSubject(emailMessage.getSubject());
mimeMessageHelper.setText("test");
javaMailSender.send(mimeMessage);
log.info("SUCCESS");
return true;
} catch (MessagingException e) {
log.info("FAIL");
throw new RuntimeException(e);
}
}
}
EmailApiController.java
package com.test.mailtest.domain.email.api;
import com.test.mailtest.domain.email.domain.EmailMessage;
import com.test.mailtest.domain.email.dto.EmailRequestDto;
import com.test.mailtest.domain.email.service.EmailService;
import com.test.mailtest.global.dto.ResponseDto;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/send-mail")
@RequiredArgsConstructor
public class EmailApiController {
private final EmailService emailService;
@PostMapping("/test")
public ResponseEntity<?> sendTestMail(@RequestBody EmailRequestDto emailRequestDto) {
EmailMessage emailMessage = EmailMessage.builder()
.userName(emailRequestDto.getUserName())
.domainAdress(emailRequestDto.getDomainAddress())
.subject("[TEST] 이메일 전송 테스트")
.build();
emailService.sendMail(emailMessage);
return ResponseEntity.ok(new ResponseDto<>(
"SUCCESS",
emailMessage.getUserName()
));
}
}
EmailRequestDto.java
package com.test.mailtest.domain.email.dto;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public class EmailRequestDto {
private final String userName;
private final String domainAddress;
}
ResponseDto.java
package com.test.mailtest.global.dto;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public class ResponseDto<T> {
private final String message;
private final T data;
}
사실.. EmailMessage에서 userName과 domainAddress 는 email 변수 하나로 관리하려 했는데, 이메일 형식에 문제가 있는지 아래와 같은 에러가 떴다.
2023-07-13 23:06:54.723 ERROR 17208 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: javax.mail.internet.AddressException: Local address contains control or whitespace in string ``{ "toEmail": "아이디@gmail.com" }''] with root cause javax.mail.internet.AddressException: Local address contains control or whitespace
at javax.mail.internet.InternetAddress.checkAddress(InternetAddress.java:1343) ~[jakarta.mail-1.6.7.jar:1.6.7]
"javax.mail.internet.InternetAddress.checkAddress(InternetAddress.java:1343)" 상세 코드
if (c <= 040 || c == 0177) throw new addressexception( "local address contains control or whitespace", addr);
이 때문에 아이디와 이메일 도메인 주소를 따로 받아서 비즈니스 로직에서 아이디@도메인주소 로 변환해줬다.
위의 오류는 내일이나 주말에 해결해보기로 하고...
결과
포스트맨으로 API를 테스트 해 본 결과, 성공적으로 잘 보내졌다고 한다.
메일함을 확인해보면 메일이 전송 된 것을 확인 할 수 있다!!
여담으로, 포스트맨에서 전송이 잘 됐다고 SUCCESS 메시지를 받았는데 메일함을 아무리 새로고침하고 기다려도 메일이 오지 않길래 뭔가 했더니..
전송하는 메일의 메일함을 가보니 친절하게 안내 메일이 와 있었다.
알고보니 gmail.com 을 google.com 으로 잘못 작성해서 그런거였다.. 😓😓
마무리
앞으로의 과제는 다음과 같다.
☑ Local address contains control or whitespace 에러 해결하기
☑ 프로젝트 성공적으로 완수하기 😁😁😁
'프로그래밍 > 스프링, 스프링부트' 카테고리의 다른 글
[SpringBoot] @RequestBody, @ResponseBody 차이 (0) | 2023.05.16 |
---|