Created
October 4, 2016 02:49
-
-
Save an-sangkil/a8927b26020a1354f5ad324b11e29402 to your computer and use it in GitHub Desktop.
Bulk Main Sender
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.knkcorp.tms.common.mail; | |
import java.util.List; | |
import javax.mail.Message; | |
import org.springframework.stereotype.Component; | |
@Component | |
public interface BaseMailSender { | |
/** | |
* 메일 발송 | |
* @param from | |
* @param to | |
* @param subject | |
* @param text | |
*/ | |
public void send(String from, String to, String subject, String text); | |
public void send(String from, String[] to , String subject , String textHTML); | |
public void send(String from, String[] to , String[] cc , String[] bcc ,String subject , String textHTML); | |
void send(List<Message> messages); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.knkcorp.tms.web.service; | |
import java.util.List; | |
import java.util.concurrent.BlockingQueue; | |
import java.util.concurrent.Callable; | |
import java.util.concurrent.ExecutionException; | |
import java.util.concurrent.ExecutorService; | |
import java.util.concurrent.Future; | |
import java.util.concurrent.LinkedBlockingQueue; | |
import java.util.concurrent.ThreadPoolExecutor; | |
import java.util.concurrent.TimeUnit; | |
import javax.inject.Inject; | |
import javax.mail.Message; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import org.springframework.stereotype.Service; | |
import com.knkcorp.tms.common.mail.BaseMailSender; | |
/** | |
* Description : 이메일을 병렬로 처리 하기 위한 ThreadExceution 서비스 | |
* BaseMailSender.java는 기본적으로 @primary 로 지정된 SmtpJavaMailService를 사용한다. | |
* | |
* BaseMailSender를 직접 인스턴스를 사용할경우. | |
* SimpleMailSender를 생성자에 주입하여 사용 할 수 있다. | |
* | |
* @author skan | |
* @since 2016. 9. 29. | |
* @version | |
* | |
*/ | |
@Service | |
public class ExecutorSendMailService { | |
private Logger logger = LoggerFactory.getLogger(getClass()); | |
@Inject | |
private BaseMailSender mailSend; | |
public ExecutorSendMailService(BaseMailSender mailSend){ | |
if(executorService == null || executorService.isTerminated()) { | |
int codeNumber = Runtime.getRuntime().availableProcessors(); | |
this.executorService = new ThreadPoolExecutor(codeNumber, codeNumber, 100L, TimeUnit.MILLISECONDS, blockingQueue); | |
logger.debug("new threadakeExecuter {} " , executorService); | |
} else { | |
logger.debug("old threadakeExecuter {} " , executorService); | |
} | |
this.mailSend = mailSend; | |
} | |
// 이메일 보낼 Thread 구분지어질 방법 | |
public enum ThreadSendEnum { | |
CALLABLE, | |
RUNNABLE | |
} | |
// executor Service 생성 | |
// static ExecutorService executorService = Executors.newFixedThreadPool(4); | |
BlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue<Runnable>(); | |
private ExecutorService executorService; | |
public void sendEmail(String from, String to, String subject, String text, ThreadSendEnum sendType) { | |
logger.trace("최대 코어 스레드수 = {}" ,Runtime.getRuntime().availableProcessors()); | |
try { | |
switch (sendType) { | |
// Return 이 필요한 경우이며, 결과반환을 위해 완료대기 까지 대기시간이 있다. | |
case CALLABLE: | |
Future<Integer> sendCountFuture = executorService.submit(new Callable<Integer>() { | |
@Override | |
public Integer call() throws Exception { | |
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService; | |
int poolSize = threadPoolExecutor.getPoolSize(); | |
String threadName = Thread.currentThread().getName(); | |
logger.info("[총 스레드 개수: " + poolSize + "] 작업 스레드 이름: " + threadName); | |
int successCount = 0; | |
mailSend.send(from, to, subject, text); | |
return successCount+1; | |
} | |
}); | |
try { | |
sendCountFuture.get(); | |
} catch (InterruptedException | ExecutionException e1) { | |
e1.printStackTrace(); | |
} | |
break; | |
// 결과값 없음 | |
case RUNNABLE : | |
executorService.submit(new Runnable() { | |
@Override | |
public void run() { | |
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService; | |
int poolSize = threadPoolExecutor.getPoolSize(); | |
String threadName = Thread.currentThread().getName(); | |
logger.info("[총 스레드 개수: " + poolSize + "] 작업 스레드 이름: " + threadName); | |
mailSend.send(from, to, subject, text); | |
} | |
}); | |
break; | |
} | |
} catch (Exception e) { | |
logger.debug("이메일 발송 에러 = {}" , e); | |
} finally { | |
//웹환경에서는 사용하지 않음. | |
//executorService.shutdown(); | |
} | |
} | |
/** | |
* 대량 메일 발송. | |
* @param messages | |
* @param sendType | |
*/ | |
public void bulkSendMail(List<Message> messages, ThreadSendEnum sendType){ | |
try { | |
switch (sendType) { | |
case CALLABLE : | |
Future<Integer> successCount = executorService.submit(new Callable<Integer>() { | |
@Override | |
public Integer call() { | |
int successCount = 0; | |
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService; | |
int poolSize = threadPoolExecutor.getPoolSize(); | |
String threadName = Thread.currentThread().getName(); | |
logger.info("[총 스레드 개수: " + poolSize + "] 작업 스레드 이름: " + threadName); | |
mailSend.send(messages); | |
return successCount+1; | |
} | |
}); | |
logger.info("발송 {} 건 중 {} 건이 발송 되었습니다.", messages.size(), successCount); | |
break; | |
case RUNNABLE : | |
executorService.submit(new Runnable() { | |
@Override | |
public void run() { | |
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService; | |
int poolSize = threadPoolExecutor.getPoolSize(); | |
String threadName = Thread.currentThread().getName(); | |
logger.info("[총 스레드 개수: " + poolSize + "] 작업 스레드 이름: " + threadName); | |
mailSend.send(messages); | |
} | |
}); | |
break; | |
} | |
} catch (Exception e) { | |
logger.debug("이메일 발송 에러 = {}" , e); | |
} finally { | |
//웹환경에서는 사용하지 않음. | |
//executorService.shutdown(); | |
} | |
} | |
// Thread 종료 | |
public void emailSendShotdown() { | |
executorService.shutdown(); | |
// 모두 종료되었는지 종료대기까지 기다린다. waiting~! | |
while (!executorService.isTerminated()) { | |
logger.info("THREAD_POOLE_XECUTOR shutdown and isWait......1"); | |
new Thread(new Runnable() { | |
@Override | |
public void run() { | |
logger.info("THREAD_POOLE_XECUTOR shutdown and isWait......2"); | |
try { | |
Thread.sleep(1000); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
} | |
}); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.knkcorp.tms.common.mail; | |
import java.util.List; | |
import java.util.Properties; | |
import java.util.concurrent.ConcurrentHashMap; | |
import javax.annotation.PostConstruct; | |
import javax.mail.Authenticator; | |
import javax.mail.Message; | |
import javax.mail.PasswordAuthentication; | |
import javax.mail.Session; | |
import javax.mail.internet.MimeMessage; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import org.springframework.context.annotation.Primary; | |
import org.springframework.mail.javamail.JavaMailSenderImpl; | |
import org.springframework.mail.javamail.MimeMessageHelper; | |
import org.springframework.stereotype.Component; | |
/** | |
* DB 환경설정의 Default 파일을 읽어와서 메일 발송 | |
* 프로퍼티 값으로 설정된 내역을 사용하지 않고, DB에 값을 사용하기 때문에 동적인 메일 셋팅이 가능한 클래스이다. | |
* | |
* @author skan | |
* @since 2016. 8. 22. | |
* @version | |
* | |
*/ | |
@Primary | |
@Component | |
public class SmtpJavaMailSender implements BaseMailSender{ | |
private Logger logger = LoggerFactory.getLogger(getClass()); | |
private String host; | |
private String protocol; | |
private int port; | |
private String username; | |
private String password; | |
private Session session; | |
public Session getSession() { | |
return session; | |
} | |
/** | |
* 전처리 : DB에서 추출한 mail 기본정보 | |
* 프로퍼티 값으로 설정된 내역을 사용하지 않고, DB에 값을 사용하기 때문에 동적인 메일 셋팅이 가능한 클래스이다. | |
*/ | |
@PostConstruct | |
public void mailConfigration() { | |
// EMail 정보에 대한 환경설정 값을 DB로 부터 읽어온다. | |
ConcurrentHashMap<String, String> mailConfigration = null; | |
if(mailConfigration == null || mailConfigration.isEmpty()) { | |
this.host = "smtp.worksmobile.com"; | |
this.protocol = "smtp"; | |
this.port = 465; | |
this.username = ""; | |
// 암/복호화 필요. | |
this.password = ""; | |
} | |
Properties props = new Properties(); | |
props.setProperty("mail.smtp.host", host); | |
props.setProperty("mail.smtp.port", port + ""); | |
props.setProperty("mail.host", host); | |
props.setProperty("mail.transport.protocol", protocol); | |
//props.setProperty("mail.smtp.localhost", "localhost"); | |
props.put("mail.smtp.ssl.enable", "true"); | |
props.put("mail.smtp.auth", "true"); | |
props.put("mail.smtp.starttls.enable", "true"); | |
props.put("mail.smtps.ssl.checkserveridentity", "true"); | |
props.put("mail.smtps.ssl.trust", "*"); | |
Authenticator auth = null; | |
if (username != null && password != null) { | |
auth = new Authenticator() { | |
protected PasswordAuthentication getPasswordAuthentication() { | |
return new PasswordAuthentication(username, password); | |
} | |
}; | |
} | |
session = Session.getInstance(props, auth); | |
} | |
@Override | |
public void send(String from, String to, String subject, String textHTML) { | |
this.send(from, new String[]{to}, subject, textHTML); | |
} | |
@Override | |
public void send(String from, String[] to, String subject , String textHTML ) { | |
this.send(from, to, null, null, subject, textHTML); | |
} | |
@Override | |
public void send(String from, String[] to, String[] cc, String[] bcc, String subject, String textHTML) { | |
JavaMailSenderImpl sender = new JavaMailSenderImpl(); | |
sender.setDefaultEncoding("utf-8"); | |
sender.setSession(session); | |
try { | |
MimeMessage message = sender.createMimeMessage(); | |
// use the true flag to indicate you need a multipart message | |
MimeMessageHelper helper = new MimeMessageHelper(message, true); | |
helper.setFrom(from); | |
helper.setTo(to); | |
// use the true flag to indicate the text included is HTML | |
helper.setSubject(subject); | |
helper.setText(textHTML, true); | |
// let's include the infamous windows Sample file (this time copied to c:/) | |
//FileSystemResource res = new FileSystemResource(new File("c:/Sample.jpg")); | |
sender.send(message); | |
logger.debug("Send Mail Success... = {}" , to.toString()); | |
} catch (Exception e) { | |
logger.error("{} 님메일 발송에 실패하였습니다. 에러메세지 = {} " , to.toString() , e.getMessage()); | |
// TODO : 메일 발송에 실패한 사용자 내역 관리. | |
} | |
} | |
/** | |
* 대량 메일 발송 | |
* @param messages | |
*/ | |
@Override | |
public void send(List<Message> messages) { | |
try { | |
JavaMailSenderImpl sender = new JavaMailSenderImpl(); | |
sender.setDefaultEncoding("utf-8"); | |
sender.setSession(session); | |
MimeMessage[] mailMessageArr = new MimeMessage[messages.size()]; | |
messages.toArray(mailMessageArr); | |
sender.send(mailMessageArr); | |
logger.debug("Send Mail Success... = {}" , mailMessageArr.toString()); | |
} catch (Exception e) { | |
logger.error("BULK 메일 발송에 실패하였습니다. 에러메세지 = {} " , e.getMessage()); | |
// TODO : 메일 발송에 실패한 사용자 내역 관리. | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment