본문 바로가기

IT/Cloud

[Amazon SES] Simple Email Service Sample

0. Table of Content

 

 

1. 개발 환경

  • STS 3.9.7
  • Spring Boot 2.2.6
  • Java 1.8

 

 

2. Dependency

plugins {
	id 'org.springframework.boot' version '2.2.6.RELEASE'
	id 'io.spring.dependency-management' version '1.0.9.RELEASE'
	id 'java'
}

group = 'com.jeonghyeong'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
	compile group: 'com.sun.mail', name: 'javax.mail', version: '1.6.2'
	
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
}

test {
	useJUnitPlatform()
}

 

AWS에서 제공하는 SDK를 사용해도 무방하나, SMTP를 사용하는데 있어서 가장 큰 요소로 작용한 것은 의존성의 용량이다.

AWS에서 제공하는 SDK와 SMTP를 이용하기 위한 의존성의 크기를 비교해보았다.

 

 

2.1. AWS SDK for SES Dependency

aws-java-sdk-ses의 의존성을 조사해본 결과 다음과 같았고, 이 의존성에 대한 용량을 파악해보기로 하였다.

 

aws-java-sdk-core + aws-java-sdk-ses + jmespath-java = 160B * 3 = 480B

 

 

 

2.2. SMTP를 이용하기 위한 Dependency

javax.mail의 의존성을 조사해본 결과 다음과 같았고, 이 의존성에 대한 용량을 파악해보기로 하였다.

 

javax.mail + javax.activation = 320B

 

의존성 용량에 대해서는 큰 차이는 없지만, 엄격하게 생각한다면 AWS-SDK를 사용하는 것 보다는 SMTP를 사용하는 방법이 컴파일 하는 시간을 단축시킬 수 있을 것이다.

 

 

 

 

 

3. Hands On Lab

SES를 처음 이용하게 되면 SES Sandbox가 설정되어 있다. Sandbox가 설정이 되어있으면, 다음과 같은 제약사항이 따른다.

	1. 하루 보낼 수 있는 제한이 200개로 제한
	2. 초당 발송 이메일 1개
	3. 등록된 이메일로만 이메일 전송 가능
Sandbox를 해제하기 위해서는 AWS Support Center에 case를 open하여 sandbox를 해제하여야 한다.

자세한 절차는 직접 콘솔에 들어가서 확인 후, 가이드에 따라서 절차를 진행하는 것을 권장한다.

 

 

 

 

먼저, 다음과 같이 SES console에서 이메일을 등록하고, 이메일 인증을 거쳐야 Amazon SES를 이용가능하다.

 

 

 

 

이메일 인증 절차를 진행하게 되면, 등록한 이메일 주소로 다음과 같은 메일이 발송된다. 메일에 첨부된 verification request link에 대해 http request를 보내면 최종적으로

SES console의 email verification status가 verified로 바뀐다. 이제 등록한 이메일을 사용할 수 있게 되었다.

 

 

 

SMTP를 이용하기 위해서는 별도의 IAM Credential이 필요하다. 다음 화면에서 발급 절차를 진행한 후, 발급된 credential를 잘 보관하길 바란다.

 

 

 

 

download한 credential정보와 Amazon SES SMTP Server Specification을 다음과 같이 spring boot의 application.properties에 기입한다.

#SES Credentials
aws.ses.username=<YOUR_SMS_CREDENTIAL_USERNAME>
aws.ses.password=<YOUR_SMS_CREDENTIAL_PASSWORD>


#Amazon SES SMTP Server Info
aws.ses.host=email-smtp.ap-south-1.amazonaws.com
aws.ses.port=587

 

 

 

이제, Email의 정보를 담을 DTO 클래스를 다음과 같이 생성한다.

package com.jeonghyeong.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor

public class Email {
	
	private String title;
	private String content;
	private String sender;
	private String receiver;

}

 

 

 

 

실질적인 테스트 이메일 발송 워크플로우를 EmailService.java에 기입 후, @Service annotation을 기입한다.

package com.jeonghyeong.service;

import java.io.UnsupportedEncodingException;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.jeonghyeong.dto.Email;


@Service
public class EmailService {
	
	@Value("${aws.ses.port}")
	private String smtpPort;
	
	@Value("${aws.ses.host}")
	private String sesHost;
	
	@Value("${aws.ses.username}")
	private String sesUsername;
	
	@Value("${aws.ses.password}")
	private String sesPassword;
	

	public void send(Email email) throws MessagingException, UnsupportedEncodingException {
		
		
        Properties props = System.getProperties();
    	props.put("mail.transport.protocol", "smtp");
    	props.put("mail.smtp.port", smtpPort); 
    	props.put("mail.smtp.starttls.enable", "true");
    	props.put("mail.smtp.auth", "true");
    	
    	Session session = Session.getDefaultInstance(props);

    	
    	System.out.println(email.getSender());
        MimeMessage msg = new MimeMessage(session);
        msg.setFrom(new InternetAddress(email.getSender(),"<EMAIL_SENDER_NICKNAME>"));
        msg.setRecipient(Message.RecipientType.TO, new InternetAddress(email.getReceiver()));
        msg.setSubject(email.getTitle());
        msg.setContent(email.getContent(),"text/html");
        
        //msg.setHeader("X-SES-CONFIGURATION-SET", "ConfigSet");
        
        Transport transport = session.getTransport();
        
        try{
            transport.connect(sesHost, sesUsername, sesPassword);	
            transport.sendMessage(msg, msg.getAllRecipients());

        }
        catch (Exception ex) {
            System.out.println("Error message: " + ex.getMessage());
        }
        finally{
            transport.close();
        }
	}
}

 

 

 

 

 

Service를 외부에 노출시키는 Rest Controller를 다음과 같이 작성해준다.

package com.jeonghyeong.controller;

import java.io.UnsupportedEncodingException;
import javax.mail.MessagingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.jeonghyeong.dto.Email;
import com.jeonghyeong.service.EmailService;

@RestController 
public class EmailController {
	
	@Autowired
	private EmailService emailService;
	
	
	@RequestMapping("/email")
	public String emailSender(@RequestParam("title") String title, @RequestParam("content") String content, @RequestParam("sender")String sender,
			@RequestParam("receiver")String receiver) throws UnsupportedEncodingException, MessagingException {
		Email email = new Email(title, content, sender, receiver);
		
		try {
			emailService.send(email);
		}catch (Exception e) {
			System.out.println(e);
		}
			
		return "Sending Email is success, Please Check your Email.";
	}
}

 

 

위 코드를 작성한 뒤,

localhost:8080/email?title=<YOUR_EMAIL_TITLE>&content=<YOUR_EMAIL_CONTENT>&sender=<REGISTERED_EMAIL_ADDRESS_IN_SES>&receiver=<EMAIL_RECEIVER_ADDRESS>

를 호출하면 다음과 같은 이메일을 받을 수 있다.

 

 

 

 

4. Source Code