[Java] Mail 발송

개발 노트/Java  2015.01.21 00:19


안녕하세요 명월입니다.
오늘은 자바환경에서 메일을 발송하는 방법에 대해 알아보도록 하겠습니다.
프로그램을 만들다 보면 알람 기능 또는 해당 데이터를 개인 저장장소에 보관시킬 일이 있습니다.
예로 휴가 신청서 시스템, 카드 결제 시스템으로 생각하면 휴가신청서의 경우는 휴가를 신청했을 때 승인자에게 신청서가 왔으니 승인해 주십시오라는 메일을 발송을 하거나 카드 결제 시스템의 경우에는 내가 카드를 사용할 떄 마다 e-mail로 내역을 발송하는 경우가 있겠네요.
의외로 메일 발송 기능은 여러 방면에서 사용하니 그 개발 방법에 대해 알고 있으면 도움이 되겠습니다.

자바에서 메일 기능을 사용하려면 아래의 세 기능 추가해야 합니다.



메일 발송 할때의 기본 형식 입니다.

package Example;
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

public class MailExam {
	public static void main(String[] args){
		try{
			new MailExam();
		}catch(Exception e){
			System.out.println("Error");
		}
	}
	public MailExam() throws Exception{
   
        Properties props = new Properties(); 
        props.setProperty("mail.transport.protocol", "smtp"); 
        props.setProperty("mail.host", "smtp.gmail.com"); 
        props.put("mail.smtp.auth", "true"); 
        props.put("mail.smtp.port", "465"); 
        props.put("mail.smtp.socketFactory.port", "465"); 
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); 
        props.put("mail.smtp.socketFactory.fallback", "false"); 
        props.setProperty("mail.smtp.quitwait", "false"); 
        
        Authenticator auth = new Authenticator(){
        	protected PasswordAuthentication getPasswordAuthentication() { 
                return new PasswordAuthentication("nowonbun@gmail.com", ""); 
            }
        };
   
        Session session = Session.getDefaultInstance(props,auth);
        
        MimeMessage message = new MimeMessage(session); 
        message.setSender(new InternetAddress("nowonbun@gmail.com")); 
        message.setSubject("test"); 

        message.setRecipient(Message.RecipientType.TO, new InternetAddress("nowonbun@naver.com")); 
        
        Multipart mp = new MimeMultipart();
        MimeBodyPart mbp1 = new MimeBodyPart();
        mbp1.setText("Test Contents");
        mp.addBodyPart(mbp1);
        
        message.setContent(mp);
        
        Transport.send(message);
	}
}


항상 저는 저 형식을 기반으로 사용하고는 했는데 이번에는 에러가 나오네요.. 에러 내용인 즉,


javax.mail.MessagingException: IOException while sending message;
  nested exception is:
	javax.activation.UnsupportedDataTypeException: no object DCH for MIME type multipart/mixed; 
	boundary="----=_Part_0_16102106.1421764935308"

이런 에러메시지이네요.. 해결 방법에 대해서는 겨우 찾기는 했으나 원인은 해석 그대로 MIME 타입이 정해지지 않았다?? 솔직히 잘 모르겠네요.. 아시는 분이 있으면 자세히 알려주세요.

해결 방법은


소스를 추가하니 해결이 되었네요..

 
MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
CommandMap.setDefaultCommandMap(mc);


결과화면입니다.


여기까지 예상대로 확인 되었습니다.
추가적으로 첨부파일을 추가하는 방법입니다.


 
package Example;
import java.io.File;
import java.util.Properties;

import javax.activation.CommandMap;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.activation.MailcapCommandMap;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

public class MailExam {
	public static void main(String[] args){
		try{
			new MailExam();
		}catch(Exception e){
			System.out.println("Error");
		}
	}
	public MailExam() throws Exception{
   
        Properties props = new Properties(); 
        props.setProperty("mail.transport.protocol", "smtp"); 
        props.setProperty("mail.host", "smtp.gmail.com"); 
        props.put("mail.smtp.auth", "true"); 
        props.put("mail.smtp.port", "465"); 
        props.put("mail.smtp.socketFactory.port", "465"); 
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); 
        props.put("mail.smtp.socketFactory.fallback", "false"); 
        props.setProperty("mail.smtp.quitwait", "false"); 
        
        Authenticator auth = new Authenticator(){
        	protected PasswordAuthentication getPasswordAuthentication() { 
                return new PasswordAuthentication("nowonbun@gmail.com", ""); 
            }
        };
   
        Session session = Session.getDefaultInstance(props,auth);
        
        MimeMessage message = new MimeMessage(session); 
        message.setSender(new InternetAddress("nowonbun@gmail.com")); 
        message.setSubject("test"); 

        message.setRecipient(Message.RecipientType.TO, new InternetAddress("nowonbun@naver.com")); 
        
        Multipart mp = new MimeMultipart();
        MimeBodyPart mbp1 = new MimeBodyPart();
        mbp1.setText("Test Contents");
        mp.addBodyPart(mbp1);

        String filename = "f:\\test.xls";
		if(filename != null){
			if(fileSizeCheck(filename)){
				MimeBodyPart mbp2 = new MimeBodyPart();
				FileDataSource fds = new FileDataSource(filename);
				mbp2.setDataHandler(new DataHandler(fds));
				mbp2.setFileName(MimeUtility.encodeText(fds.getName(), "UTF-8", "B"));
			
				mp.addBodyPart(mbp2);
			}else{
				throw new Exception("file size overflow !");
			}
		}
        
		MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
		mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
		mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
		mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
		mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
		mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
		CommandMap.setDefaultCommandMap(mc);
        
        message.setContent(mp);
        
        Transport.send(message);
	}
	 protected boolean fileSizeCheck(String filename) {
        if (new File(filename).length() > (1024 * 1024 * 2.5)) {
            return false;
        }
        return true;
    }
}

결과 화면입니다.


예상대로 결과를 얻었습니다. 오늘은 여기까지 입니다.


댓글 7개가 달렸습니다.
댓글쓰기
  1. sangheum
    2015.01.24 17:46 신고 |  수정/삭제  댓글쓰기

    javamail 을 활용한 메일 전송을 구현해보기 위해.. 명월님이 올려준 대로 해 봤는데요..

    error : javax.mail.MessagingException: Could not connect to SMTP host: smtp.gmail.com, port: 465;
    nested exception is:
    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target


    가 발생하네요.

    포트를 587로도 바꿔봤는데요..

    안되요.. 무슨 문제가 있는걸까요??

    • 明月 v명월v
      2015.01.25 00:57 신고 |  수정/삭제

      안녕하세요. 먼저 블로그 방문 감사합니다...
      에러 내용 만으로는 정확한 진단이 힘들지만 인증처리에서 에러가 난 듯 싶네요...
      메일을 보내기 전에 ID,PW를 넣는 부분이 있는데...소스로 치면 44번줄 입니다.
      제 개인정보라 제 이메일 주소는 넣어지만 패스워드는 제거된 상태입니다. 그 부분에 본인의 ID,PW를 넣고 해보세요... 정 안되시면 메일로 소스 보내주시면 확인 해 보겠습니다.

  2. sangheum
    2015.01.26 09:43 신고 |  수정/삭제  댓글쓰기

    넵.. 지금 집이 아니라... 소스를 보내 드릴 순 없지만, 명월님이 했던 소스 그대로 입니다.

    물론 id, pw 다 집어 넣고 해봤구요.. 단 다른 점이 있다면,

    첨부 파일 넣는 부분은 제가 뺐어요... 메일 발송이 주된 목적이였기에..

    혹시

    첨부 파일 넣는 부분을 빼서 발생하는 오류일까요??

    • 明月 v명월v
      2015.01.27 00:16 신고 |  수정/삭제

      에러의 내용은 인증서를 확인 할 수 없는 에러 입니다.
      첨부파일때문에 나는 에러는 아니구요..
      소스를 직접확인 못하는 상황에서 예상해 볼 수 있는 건
      Gmail 이 아닌 다른 mail을 사용하는 데 그 메일이 smtp를 지원하지 않는 경우.포트 번호가 다르다던가..
      둘째는 자체메일을 사용하는데 거기의 인증서가 걸린 것입니다.
      JVM 파일에 해당 메일 인증서를 추가해주는 작업이 필요합니다.

      참고 -
      http://stackoverflow.com/questions/6908948/java-sun-security-provider-certpath-suncertpathbuilderexception-unable-to-find
      참고2 -
      http://stackoverflow.com/questions/9619030/resolving-javax-net-ssl-sslhandshakeexception-sun-security-validator-validatore

  3. leejinseong
    2016.06.18 17:03 신고 |  수정/삭제  댓글쓰기

    안녕하세요.
    그대로 따라 했는데 Error라고 오류만 뜨네요... 뭐가 문제인건가요

  4. taehunnim
    2016.08.24 16:07 신고 |  수정/삭제  댓글쓰기

    정말 감사합니다 ㅠ_ㅠ 잘돼요!!

  5. 슈퍼개발자
    2017.01.10 12:31 신고 |  수정/삭제  댓글쓰기

    안녕하세요. 주인장님. 블로그 글도 참 잘 쓰시고 디자인도 깔끔하니 이쁘네요.
    문의 드릴게있어서요.ㅠㅠ
    블로그에서 사용하고 계신 폰트 좀 알려주시면 안될까여