본문 바로가기

프로그래밍/스프링, 스프링부트

[Spring Boot] JavaMail을 이용하여 메일 전송하기 (+ PostMan)

 

진행 중인 프로젝트에서 사용자에게 "임시 비밀번호 발급 및 이메일 인증 서비스"를 구현해야 했기 때문에

Spring Boot를 이용하여 메일을 전송하는 기능을 공부해보려 메일 전송 테스트를 해봤다.

 

환경

⚙ jdk 11
⚙ spring boot 2.7.13
⚙ Intellij 

 

준비사항

✔ 메일을 보내기 위해선 아래 두가지 설정이 필요하다.

✅ pop3 : 메시지를 여러 장치에서 읽음으로 표시하는 기능
✅ SMTP(Simple Mail Transfer Protocol) : 전자 메일 전송을 위한 표준 프로토콜

나는 보내는 메일 주소를 gmail로 하였기 때문에 gmail에서 두가지 설정을 해주었다.

 

 

✔ 다음으로, 스프링 부트를 이용하여 메일을 보내기 위해선 Spring Boot Starter Mail 의존성이 필요하다.

✔ 이외에 application.yml에서 메일 관련 세팅을 해줘야 하는데, 초기 환경 세팅 및 코드 참조는 아래 블로그에서 참고했다.

 

yeonk.log

 

Spring Boot | 메일 발송 기능 구현하기 (Gmail)

Spring Boot, Java, Gmail을 이용하여 메일 발송 기능 구현하기

velog.io

 

참고한 블로그에서는 임시 비밀번호와 이메일 인증 번호를 전송하는 기능을 구현하였지만,

나는 간단하게 메일 전송 기능만 구현해보고 싶어서 해당 부분은 다 쳐내고 따로 "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);

 

이 때문에 아이디와 이메일 도메인 주소를 따로 받아서 비즈니스 로직에서 아이디@도메인주소 로 변환해줬다.

위의 오류는 내일이나 주말에 해결해보기로 하고... 

 

결과

Postman

포스트맨으로 API를 테스트 해 본 결과, 성공적으로 잘 보내졌다고 한다.

 

 

mail

메일함을 확인해보면 메일이 전송 된 것을 확인 할 수 있다!!

 

여담으로, 포스트맨에서 전송이 잘 됐다고 SUCCESS 메시지를 받았는데 메일함을 아무리 새로고침하고 기다려도 메일이 오지 않길래 뭔가 했더니..

 

잘못 전송..

전송하는 메일의 메일함을 가보니 친절하게 안내 메일이 와 있었다.

알고보니 gmail.com 을 google.com 으로 잘못 작성해서 그런거였다.. 😓😓

 

마무리

앞으로의 과제는 다음과 같다.

☑ Local address contains control or whitespace 에러 해결하기
☑ 프로젝트 성공적으로 완수하기 😁😁😁

 

Recent Posts
Popular Posts