신입 개발자가 되기 위해 공부했던 독학 자료들/Spring

[스프링] 메일서버(SMTP Server)를 이용한 메일 전송

Seojoo21 2022. 3. 19. 20:13

0. 개요 

SMTP : Simple Mail Transfer Protocol의 약자로 전자 메일 전송을 위한 표준 프로토콜 

SMTP Server : 이메일을 송신하는 서버.

(메일 서버는 SMTP Server, POP3 Server가 있는데 POP3 Server는 이메일을 수신하는 서버이다.)

 

 메일 전송 기능을 구현하기 위해선 아래의 4가지가 필요하다.

     1. pom.xml 설정

     2. mailSender Bean 등록(root-context.xml 또는 servlet-context.xml)

     3. Controller 메서드 추가

     4. 메일 계정 보안 설정

 

메일서버(SMTP Server)를 통해 메일을 전송할 때 다음과 같은 두 가지 방법이 있다. 

1) 메일 서버가 릴레이(relay)를 허용하는 경우 

* 릴레이(Relay): 외부(외부 네트워크)에서 해당 메일 서버(SMTP 서버)를 경유해서 외부로 메일을 보내는 것을 의미한다.

이 방법은 계정이 존재하지 않더라도 메일을 발송할 수 있다.

하지만 릴레이를 허용하는 경우 잘못된 방식(타인에 의한 스팸 메일)으로 악용될 수 있기 때문에 특정 IP에서만 릴레이가 되도록 하는 것이 일반적이다.

 

2) 메일 서버에 계정 인증 후 메일을 전송하는 방법

 

위의 두 가지 방법 중 어떤 것을 선택할지는 mailSender에 Bean을 등록할 때 이루어진다.

위의 두 가지 방법 중 여기에서는 '2) 메일 서버에 계정 인증 후 메일을 전송하는 방법' 을 알아본다. 

 

1. 메일 계정 보안 설정

SMTP Server를 통해서 메일 전송 기능을 구현하기 위해서는 사용하고자 하는 메일의 SMTP 보안 단계를 낮추어야 한다. 

구글, 네이버, 다음 등 각 웹사이트에서는 이메일 계정 환경 설정 부분에 SMTP 보안 단계를 조절할 수 있는 메뉴가 있다.

여기에서는 구글 계정과 네이버 계정의 SMTP 보안 설정을 조절하는 방법을 살펴본다.

 

1-1. 구글 

 

1) 먼저 구글에서 자신의 계정에 로그인을 한 후 '구글 계정 관리'에 들어간다. 

 

2) 왼쪽 메뉴 중 '보안'을 클릭한다. 

3) 보안 항목에서 '보안 수준이 낮은 앱의 엑세스'를 찾은 후 '엑세스 사용 설정(권장하지 않음)'을 클릭한다.  

 

4) 보안 수준이 낮은 앱 허용을 '사용함'으로 변경한다. 

1-2. 네이버 

1) 네이버 메일 페이지에 들어간 후 왼쪽 하단에 있는 '환경설정'을 클릭한다. 

 

2) 상단에 있는 'POP3/IMAP' 설정을 클릭한다.  

3) 'POP3/SMTP 사용'을 '사용함'으로 체크 후 확인 버튼을 누른다. 

 

2. pom.xml 설정

1) maven repository에 가서 javax.mail 라이브러리를 찾아 pom.xml에 설정해준다.

이 라이브러리는 java에서 메일을 보내기 위해 필요한 라이브러리로 실제 전송되는 메일 객체를 가진다.

주요 클래스로는 Session, Message, Address, Authenticator 등이 있고 해당 라이브러리만으로도 메일 전송 기능을 구현할 수 있지만 개발자가 모든 세팅을 직접 해주어야한다. 

대신 spring-context-support 라이브러리를 함께 사용하면 mail 라이브러리에서는 javax.mail.intertnet.MimeMessage만 사용하여 보다 쉽게 메일 전송 기능을 처리할 수 있다. 

 

2) maven repository에 가서 spring-context-support 라이브러리를 추가한다.

이 라이브러리는 JavaMailSender 인터페이스(JavaMailSenderImpl)를 사용하기 위해 필요로 한다. mail 라이브러리를 일일이 셋팅할 필요 없이 몇 가지의 설정(MailSender Bean설정)만으로도 사용할 수 있도록 도와준다.

 

JavaMailSender 인터페이스는 MIME 형식의 메일을 보낼 수 있도록 해준다. (javax.mail.MimeMessage 사용 가능)

 

스프링 프레임워크에는 기본적으로 JavaMailSender 인터페이스와 비슷한 역할을 하는 MainSender 인터페이스가 있으나 MainSender는 SimpleMailMessage만 사용 가능하다. (javax.mail.MimeMessage 사용 불가능)

 

* SimpleMailMessage: 단순한 텍스트 메세지 전송만 가능

* MimeMessage: 텍스트와 더불어 이미지 같은 첨부파일을 메세지에 포함시켜 전송 가능 

 

3. mailSender Bean 등록

Bean 등록은 root-context.xml에 설정해주면 된다. 

'릴레이를 허용하는 서버를 사용하는 경우의 빈 설정 방법'과 '메일 서버에 계정 인증 후 메일을 전송하는 방법'이 다르다.

여기서는 '메일 서버에 계정 인증 후 메일을 전송하는 방법'을 살펴본다.

 

3-1. 메일 서버에 계정 인증 후 메일을 전송 하는 방법

1) Gmail

root-context.xml에 아래의 코드를 추가한다.

<!-- gmail설정 -->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> 
    <property name="host" value="smtp.gmail.com" />
    <property name="port" value="587" />
    <property name="username" value="your_email"/> <!-- 자신의 이메일 아이디 -->
    <property name="password" value="your_password!"/> <!-- 자신의 비밀번호 -->
 <!-- 보안연결 TLS과 관련된 설정 -->
    <property name="javaMailProperties">
    <props>
       <prop key="mail.smtp.auth">true</prop>
       <prop key="mail.smtp.starttls.enable">true</prop>
    </props>
    </property>
</bean>

* host: "smtp.gmail.com" 입력 

* port: "587" 입력

* username: 자신의 이메일 아이디 입력 (도메인까지 입력해야함. 예: xxxx@gmail.com) 

* password: 자신의 이메일 비밀번호 입력 

* javaMailProperties인 <property> 태그에 삽입된 코드는 TLS 인증 코드이다. 

 

** SSL: 웹사이트와 브라우저 사이에서 전송되는 데이터를 암호화하여 인터넷 연결 보안을 유지하는 표준 기술. 

** TLS: 더 강력한 버전의 SSL로 TLS도 SSL이라 불리기도 한다. 

 

2) Naver

root-context.xml에 아래의 코드를 추가한다. 

<!-- navermail설정 -->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> 
 <property name="host" value="smtp.naver.com"/> <!-- 메일 서버 호스트 -->
 <property name="port" value="465"/> <!-- 메일 서버 포트번호 -->
 <property name="username" value="your_email"/> <!-- 자신의 이메일 아이디 -->
 <property name="password" value="your_password"/> <!-- 자신의 비밀번호 -->
 <!-- 보안연결 SSL과 관련된 설정 -->
 <property name="javaMailProperties">
  <props>
  <prop key="mail.smtp.auth">true</prop>
  <prop key="mail.smtp.starttls.enable">true</prop>
  <prop key="mail.smtps.checkserveridentity">true</prop>
  <prop key="mail.smtps.ssl.trust">*</prop>
  <prop key="mail.debug">true</prop>
  <prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
  <prop key="mail.smtp.ssl.enable">true</prop> 
  </props>
 </property>
</bean>

* host : "smtp.naver.com" 입력

* port : "465" 입력

* username : 자신의 이메일 아이디 입력 (지메일과 달리 @naver.com 은 제외하고 아이디 자체만 입력하면 됨) 

* password : 자신의 이메일 비밀번호 입력

* javaMailProperties인 <property> 태그에 삽입된 코드는 SSL 인증 코드이다. 

 

4. Controller 메서드 추가 

실제 메일을 전송할 때 아래와 같이 두 가지 방법이 있다.

1) MimeMessage 객체를 직접 생성하여 메일을 발송하는 방법

2) MimeMessagePreparator를 사용하여 메일을 발송하는 방법

 

메일을 보낼 때는 '보내는이 이메일, 받는이 이메일, 메일 제목, 메일 내용' 4가지의 데이터를 입력해줘야하는데 해당 데이터들을 객체에 담아서도 가능하고 Controller 메서드 내에 직접 삽입하는 것도 가능하다. 여기서는 직접 삽입 방식으로 진행해보겠다. 

 

MailController 클래스를 생성하고 메일 전송을 위해 root-context.xml에 등록한 Bean을 주입해준다. 

 

4-1. MimeMessage 객체를 직접 생성하여 메일을 발송하는 방법

이 방식을 이용하기 위해 import 되는 클래스들은 아래와 같다. 

import javax.mail.internet.MimeMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;

* MimeMessage 대신 SimpleMailMessage를 사용할 수도 있다. 

* MimeMessage: 멀티파트 데이터 처리 가능 

* SimpleMailMessage: 단순한 텍스트 데이터만 전송 가능 

 

MailController에 아래와 같이 메서드를 작성한다. 

import javax.mail.internet.MimeMessage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MailController {
	
	@Autowired
	private JavaMailSender mailSender;
	
	@GetMapping("/sendMail")
	public void sendMailTest() throws Exception {
		
		String subject = "test 메일";
		String content = "메일 테스트 내용";
		String from = "보내는 이 아이디@도메인 주소";
		String to = "받는 이 아이디@도메인 주소";
		
		try {
			MimeMessage mail = mailSender.createMimeMessage();
			MimeMessageHelper mailHelper = new MimeMessageHelper(mail, true, "UTF-8");
			//true: 멀티파트 메세지를 사용하겠다는 의미 
			
            /* 단순한 텍스트 메세지만 사용시엔 아래의 코드도 사용 가능 
             * MimeMessageHelper mailHelper = new MimeMessageHelper(mail,"UTF-8");
             */
			
			mailHelper.setFrom(from);
			// 빈에 아이디 설정한 것은 단순히 SMTP 인증을 받기 위해 사용한 것. 따라서 보내는이(setFrom()) 또한 반드시 필요.
            // 보내는 이의 메일 주소와 이름이 모두 표기 되기를 원한다면 아래의 코드를 사용하면 된다.
            // mailHelper.setFrom("보내는이 이름 <보내는이 아이디@도메인주소>");
			mailHelper.setTo(to);
			mailHelper.setSubject(subject);
			mailHelper.setText(content, true ); 
			//true: html을 사용하겠다는 의미 
			/*단순한 텍스트만 사용한다면 아래 코드를 사용하면 된다.
			mailHelper.setText(content); */
			
			mailSender.send(mail);
			
		}catch(Exception e){
			
			e.printStackTrace();}
		
	}

}

 MimeMessageHelper mailHelper = new MimeMessageHelper(mail, true, "UTF-8") 에서 true는 멀티파트 메세지를 사용하겠다는 의미이다. 단순한 텍스트 메세지만 사용한다면 아래의 코드를 사용하면 된다. 

MimeMessageHelper mailHelper = new MimeMessageHelper(mail,"UTF-8");

 

mailHelper.setText(content, true) 에서 true는 html을 사용한다는 의미이다. html을 사용하게 되면 이미지를 첨부 할 수 있는 <img>태그를 사용 할 수 있다. 

 

단순한 텍스트만 사용할 시엔 mailHelper.setText(content)를 사용하면 된다. 

 

보내는이(from)은 반드시 있어야 한다. mailSender 빈에서 아이디를 기입하였지만 이는 SMTP 사용 권한을 얻어 오는 역할을 수행한다.

 

메일 주소에 보내는 이와 메일 주소를 모두 표기하길 원한다면 아래와 같이 작성하면 된다.

mailHelper.setFrom("보내는이 이름 <보내는이 아이디@도메인주소>");

 

4-2. MimeMessagePreparator를 사용하여 메일을 발송하는 방법

이 방법은 MimeMessage를 직접 객체화하지 않고 MimeMessagePreparator 클래스를 사용하는 방식이다. 

이 방법을 사용하기 위해 import되는 클래스는 다음과 같다.

 

앞서 살펴본 4-1과 다른 점은 import org.springframework.mail.javamail.MimeMessagePreparator 가 추가된다는 것이다. 

import javax.mail.internet.MimeMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;

MailController에 아래와 같이 메서드를 작성한다. 

 

import javax.mail.internet.MimeMessage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MailController {
	
	@Autowired
	private JavaMailSender mailSender;
	
	@GetMapping("/sendMail")
	public void sendMailTest() throws Exception {
		
		String subject = "test 메일";
		String content = "메일 테스트 내용";
		String from = "보내는 이 아이디@도메인 주소";
		String to = "받는 이 아이디@도메인 주소";

		final MimeMessagePreparator preparator = new MimeMessagePreparator() {
			
			public void prepare(MimeMessage mimeMessage) throws Exception{
				final MimeMessageHelper mailHelper= new MimeMessageHelper(mimeMessage, true, "UTF-8");
				
				mailHelper.setFrom(from);
				mailHelper.setTo(to);
				mailHelper.setSubject(subject);
				mailHelper.setText(content, true);
				
			}
		};
		
		try {
			mailSender.send(preparator);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

 

5. 텍스트 / 이미지 / 업로드 전송

 

이미지, 업로드 전송을 위해서는 멀티파트 메세지와 html 허용을 해주어야 한다. 

// 멀티파트 메세지 허용 (true)
MimeMessageHelper mailHelper = new MimeMessageHelper(mail,true,"UTF-8");
 
// html 허용 (true) 
mailHelper.setText(content, true);

 

5-1. 단순 텍스트

앞서 살펴본 4-1 코드 예시가 메세지 내용을 단순한 텍스트로 전송하는 것이다. 

 

5-2. 이미지

이미지를 첨부하는 방법은 html 허용을 true로 설정했기 때문에 이미지 태그 <img>를 사용한다. 

예를 들면 아래와 같다.

String content = "메일 테스트 내용" + "<img src=\"이미지 경로\">";

 

5-3. 업로드 전송 

업로드 된 파일을 전송하기 위해서는 추가적인 클래스 import가 필요하다.

import org.springframework.core.io.FileSystemResource;
import java.io.File;

 

추가해주어야 할 코드는 아래와 같다.

FileSystemResource file = new FileSystemResource(new File("경로\업로드할파일.형식")); 
helper.addAttachment("업로드파일.형식", file);

 

6. 메일 전송 테스트 

MailControllerTests 클래스를 통해 Controller 메서드에 추가했던 코드들을 테스트 해보자.

import java.io.File;

import javax.mail.internet.MimeMessage;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
public class MailControllerTests {
	
	@Autowired
	JavaMailSenderImpl mailSender;
	
	String subject = "test 메일";
	String content = "메일 테스트 내용" + "<img src=\"이미지파일경로\">";
	String from = "보내는 이 아이디@도메인 주소";
	String to = "받는 이 아이디@도메인 주소";
	
	// 4-1. MimeMessage 객체를 직접 생성하여 메일을 발송하는 방법
	@Test
	public void sendMailTest1() throws Exception {
		
		
		try {
			MimeMessage mail = mailSender.createMimeMessage();
			MimeMessageHelper mailHelper = new MimeMessageHelper(mail, true, "UTF-8");
			
			mailHelper.setFrom(from);
			mailHelper.setTo(to);
			mailHelper.setSubject(subject);
			mailHelper.setText(content, true ); 
			
			FileSystemResource file = new FileSystemResource(new File("파일경로"));
			mailHelper.addAttachment("업로드파일.형식 ", file);
			
			mailSender.send(mail);
			
		}catch(Exception e){
			
			e.printStackTrace();
		}
	}
		
	// 4-2. MimeMessagePreparator를 사용하여 메일을 발송하는 방법
	@Test
	public void sendMailTest2() throws Exception{
		
		try {
			
			final MimeMessagePreparator preparator = new MimeMessagePreparator() {
				
				public void prepare(MimeMessage mimeMessage) throws Exception{
					final MimeMessageHelper mailHelper= new MimeMessageHelper(mimeMessage, true, "UTF-8");
					
					mailHelper.setFrom(from);
					mailHelper.setTo(to);
					mailHelper.setSubject(subject);
					mailHelper.setText(content, true);
					
				}
			};

			mailSender.send(preparator);
			
		}catch(Exception e){
			e.printStackTrace();
		}
		
	}
		
}

테스트에 성공하면 메일이 잘 들어오는 것을 볼 수 있다. 

 

 

출처: https://kimvampa.tistory.com/92