오늘은 어디로 갈까...

JavaMail SMTP를 이용한 메일 전송 본문

낙서

JavaMail SMTP를 이용한 메일 전송

剛宇 2009. 4. 14. 17:56

 지난 시간에는 실제적인 메일 전송은 하지 않고, 로그로만 출력했는데, 찜찜한 관계로 한번 해보도록 하자.
 자바 진영에서는 JavaMail이라는 훌륭한(?) 메일 라이브러리를 제공한다. IMAP/POP3/SMTP를 지원한다. 이 JavaMail을 사용하기 위해서는 JAF(JavaBeans Activation Framework)가 필요하다. JDK 1.6부터는 자체적으로 포함되어있다. 여기서는 JDK 1.5를 사용하는 관계로 다운 받도록 하겠다.

1. 라이브러리 설치하기
 - JavaMail의 mail.jar과 JAF의 activation.jar을 클래스패스에 잡아주자.(mail.jar는 mailapi.jar + imap.jar + smtp.jar + pop3.jar라고 보면 된다.)

JavaMail 1.4.2
http://java.sun.com/products/javamail/downloads/index.html

JavaBeans Activation Framework 1.1.1
http://java.sun.com/javase/technologies/desktop/javabeans/jaf/downloads/index.html

2. SMTPMailSendManager 클래스 만들기
 - MailSendManager 인터페이스를 구현한 SMTPMailSendManager 클래스를 만들어보자.

package kr.kangwoo.postman.service;

import java.io.UnsupportedEncodingException;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import kr.kangwoo.postman.core.MailException;
import kr.kangwoo.postman.core.MailStatusCode;
import kr.kangwoo.postman.core.MessageException;
import kr.kangwoo.util.StringUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SMTPMailSendManager implements MailSendManager {

	private Logger logger = LoggerFactory.getLogger(getClass());
	
	private String protocol = "smtp";
	private String type = "text/html; charset=KSC5601";
	
	private String userName;
	private String password;
	private String host = "127.0.0.1";
	private int port = 25;
	private boolean starttlsEnable = false;

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public void setType(String type) {
		this.type = type;
	}
	
	public void setStarttlsEnable(boolean starttlsEnable) {
		this.starttlsEnable = starttlsEnable;
	}

	public void send(String toAddress, String toName, String fromAddress,
			String fromName, String subject, String content) throws MessageException {
		logger.debug("[{}] 메일 발송 시작", toAddress);
		try {
			Properties props = new Properties();
			props.put("mail.transport.protocol", protocol);
			props.put("mail.smtp.host", host);
			props.put("mail.smtp.port", String.valueOf(port));
			
			Authenticator authenticator = null;
			if (StringUtils.isNotBlank(userName)) {
				props.put("mail.smtp.auth", "true");
				authenticator = new SMTPAuthenticator(userName, password);
			}
			
			if (starttlsEnable) {
				props.put("mail.smtp.starttls.enable", Boolean.toString(starttlsEnable));	
			}
			
			Session session = Session.getInstance(props, authenticator);

			MimeMessage message = new MimeMessage(session);
			message.setFrom(new InternetAddress(fromAddress, fromName));
			message.addRecipient(Message.RecipientType.TO, new InternetAddress(toAddress, toName));
			message.setSubject(subject);
			message.setContent(content, type);

			Transport.send(message);
			logger.debug("[{}] 메일 발송 성공", toAddress);
		} catch (UnsupportedEncodingException e) {
			logger.debug("[{}] 메일 발송 실패", toAddress);
			throw new MailException(MailStatusCode.SEND_FAIL, "메일을 발송하는 중 에러가 발생했습니다.", e);
		} catch (MessagingException e) {
			logger.debug("[{}] 메일 발송 실패", toAddress);
			throw new MailException(MailStatusCode.SEND_FAIL, "메일을 발송하는 중 에러가 발생했습니다.", e);
		}
	}

	class SMTPAuthenticator extends Authenticator {
		
		PasswordAuthentication passwordAuthentication;
		
		SMTPAuthenticator(String userName, String password) {
			passwordAuthentication = new PasswordAuthentication(userName, password);
		}
		public PasswordAuthentication getPasswordAuthentication() {
			return passwordAuthentication;
		}
	}

}

- 자바메일을 이용해서 메일 전송을 구현하였다. 사용자 인증을 위해서 Authenticator을 상속받은 SMTPAuthenticator 클래스를 내부에 만들었다. 그리고 starttls을 사용하기 위해 변수를 선언하였다. (starttls게 뭔지 본인은 모른다. 궁금하신분은 RFC-2487)를 참고 바란다.

3. PostMan 실행해보기
- 지난 시간에 만든 PostMan 클래스를 수정해주자. 로그로만 메일 내용을 출력해주던 SimpleMailSendManager 클래스를 지금 만든 SMTPMailSendManager 클래스로 바꾸자.
package kr.kangwoo.postman.core;

public class PostMan {
	// ... 생 략 ...
	public static void main(String[] args) {
		PostMan man = new PostMan();
		MailDao mailDao = new SimpleMailDao();
		MailTemplateDao mailTemplateDao = new SimpleMailTemplateDao();
		SimpleMailManager mailManager = new SimpleMailManager();
		mailManager.setMailDao(mailDao);
		FreemarkerMailTemplateManager mailTemplateManager = new FreemarkerMailTemplateManager();
		mailTemplateManager.setMailTemplateDao(mailTemplateDao);
		
		SMTPMailSendManager mailSendManager = new SMTPMailSendManager();
		mailSendManager.setHost("smtp.gmail.com");
		mailSendManager.setPort(587);
		mailSendManager.setStarttlsEnable(true);
		mailSendManager.setUserName("계정명");
		mailSendManager.setPassword("계정비밀번호 ");
		
		man.setMailManager(mailManager);
		man.setMailTemplateManager(mailTemplateManager);
		man.setMailSendManager(mailSendManager);
		
		man.run();
	}

}


- 여기서는 gmail 계정을 사용하였다.(gmail 계정을 사용할려면 starttls를 사용함으로 해야한다.) 발송할 대상을 바꾸고(꼭 바꿔주시길 바란다.!!! 지난 예제로 실행하면 본인한테 메일이 온다.) 실행해보자.
- 어제 소스를 그대로 사용하시는분은, 무한 루프를 도는 관계로 꼭 강제적으로 중지시켜주기 바란다. 안그러면 미워할거다.

- gmail, naver, daum은 잘 도착한다. ^^;