주요글: 도커 시작하기
반응형
Java Mail API에 대해서 알아본다.

Java Mail API

기존에 자바에서 메일과 관련된 프레임워크를 개발하기 위해서 개발자들은 스스로 전체적인 메일 시스템을 설계하고 구현해야만 했다. 하지만, Java Mail API가 발표되면서, 개발자들은 메일 시스템의 프레임워크를 설계하는 데 고민할 필요가 없어졌으며, 또한 Java Mail API와 함께 제공되는 클래스들(SMTP, POP3, IMAP을 구현하였다)을 사용하여 매우 손쉽게 메일을 주고 받는 시스템을 구축할 수 있게 되었다.

이 글에서는 Java Mail API가 무엇이며, 어떻게 구성되어 있는 지 살펴볼 것이며, 다음 기사에서는 Java Mail API를 이용하여 간단한 웹 기반의 메일 시스템을 구현해볼 것이다.

Java Mail API의 주요 목적은 개발자들이 손쉽게 어플리케이션의 메일 기능을 추가하고 또한 정교한 사용자 인터페이스를 생성할 수 있도록 하는 것이다. Java Mail API는 Message, Transport, Session과 같이 메일의 공통적인 기능과 프로토콜을 추상화한 클래스를 포함하고 있으며, 또한 자바 기반이기 때문에 자바 플랫폼에서 제공하는 다양한 API를 사용할 수 있다. 다음 그림은 Java Mail API의 전체적인 구조를 보여주고 있다.


위 그림을 보면 가장 상위에 메일 시스템을 사용하는 어플리케이션 위치하는 것을 알 수 있다. 이 어플리케이션은 Java Mail의 추상 클래스를 통해서 실제 구현 클래스 계층에 접근하게 된다. 구현 클래스 계층은 하부에 있는 실제 이메일 시스템 구현 계층과 상호작용한다.메일의 컨텐츠와 관련된 데이터는 JAF(JavaBean Activation Framework)를 사용하여 표현할 수 있다. 일반적으로 Java Mail API를 사용하는 어플리케이션은 다양한 포맷을 제공하기 위해 JAF를 통해 메일 메시지의 컨텐츠를 생성한다.

JavaMail 프레임워크

Java Mail API는 다음과 같은 기능을 수행하는 것을 기본 목적으로 한다.

  • 헤더와 데이터로 구성된 메일 메시지를 생성한다. Java Mail은 메일 메시지를 정의하기 위해 Message 클래스를 사용한다.
  • Session 객체를 생성한다. 이 객체는 사용자를 인증하고 메시지 저장과 전송에 대한 접근을 제어한다.
  • 메시지를 전송한다.
  • 메시지 저장소로부터 메시지를 읽어온다.
  • 읽은 메시지에 명령어를 수행한다. '보기'나 '출력' 같은 명령어는 JAF를 인식하는 자바빈에서 구현하도록 하고 있다.
일반적으로 이러한 기능은 메일 클라이언트가 기본적으로 제공하는 것들이다. 전체 프레임워크를 그림으로 나타내면 다음과 같다.



Java Mail API의 주요 구성 요소

이 글에서는 Java Mail API의 모든 클래스에 대해서 알아보지는 않을 것이며, 가장 중심적인 역할을 하는 클래스인 javax.mail.Session, javax.mail.Store, javax.mail.Transport, javax.mail.Folder, javax.mail.Message 클래스에 대해서 알아볼 것이다. 실제로 이 다섯개의 클래스만 알맞게 사용하면 매우 손쉽게 메일 시스템을 구축할 수 있다.

javax.mail.Session

javax.mail.Session은 Java Mail API를 사용하는 출발점이 되는 클래스로서 다양한 메일 프로토콜을 위한 서비스 프로바이더 구현(Service Provider Implementation; SPI)을 나타내는 클래스를 로딩하고 제어할 수 있는 메소드를 제공하고 있다. 예를 들어, javax.mail.Store 클래스의 인스턴스는 javax.mail.Session 클래스를 통해서 구할 수 있다. (여기서 서비스 프로바이더는 Java Mail API를 이용하여 구현 클래스 계층을 제공하는 개발자는 벤더를 의미한다. 현재 Java Mail API는 IMAP, SMTP, POP3 프로토콜에 대한 구현 계층을 제공하고 있다.)

javax.mail.Store

javax.mail.Store 클래스는 특정한 메일 프로토콜을 이용하여 메일의 읽기, 쓰기, 감시, 검색 등을 할 수 있도록 해 준다. Session 클래스를 사용하여 구할 수 있으며, 메일 저장소를 추상화한 javax.mail.Folder에 접근할 수 있도록 해 준다. 서비스 프로바이더는 Store 클래스를 알맞게 구현해야 한다.

javax.mail.Folder

javax.mail.Folder 클래스는 메일 메세지에 계층적 구조를 제공하며 메일 메세지에 접근할 수 있도록 해 준다. 메일 메세지는 javax.mail.Message 클래스의 객체로 표현된다. 서비스 프로바디어는 Folder 클래스를 알맞게 구현해야 한다.

javax.mail.Transport

javax.mail.Transport 클래스는 특정한 프로토콜을 사용하여 메세지를 전송할 때 사용된다. 서비스 프로바이더는 이 클래스를 알맞게 구현해야 한다.

javax.mail.Message

javax.mail.Message 클래스는 주제, 수신자의 이메일주소, 발송자의 이메일 주소, 보낸 날짜와 같은 실제 이메일 메세지의 세부 사항을 나타낸다. 서비스 프로바이더는 자신이 사용하는 프로토콜에 알맞게 Message를 구현해야 한다.

Java Mail API와 JAF

Java Mail API는 메시지에 다양한 포맷을 사용할 수 있도록 하기 위해 JAF를 사용한다. JAF는 별도의 확장 API로서 다양한 데이터 형식을 이용하여 작업하는 방법을 통합하기 위해 작성되었다. 실제로 JAF를 이용하면 간단한 텍스트 데이터에서부터 이미지, 비디오 등의 매우 복잡한 멀티 미디어 데이터로 구성된 문서까지 다양한 데이터를 제공할 수 있다.

예제 어플리케이션

여기서 사용할 예제는 일정 시간 동안 메일 박스를 검사하는 어플리케이션이다. 예제 어플리케이션은 POP3를 사용하기 때문에, 이 예제를 실행하기 위해서는 POP3를 지원하는 메일 시스템에 이메일 계정을 갖고 있어야 한다.

예제 어플리케이션을 실행하기 위해서는 Java Mail API와 JAF API가 필요하다. 이 두 API는 각각 http://java.sun.com/products/javamail/index.htmlhttp://java.sun.com/products/javabeans/glasgow/jaf.html에서 다운로드 받을 수 있다. Java Mail API 1.2를 다운로드 받은 후 압축을 풀면 mailapi.jar, mail.jar, pop.jar, smtp.jar, imap.jar 파일이 생성된다. 여기서 mail.jar는 mailapi.jar, pop3.jar, smtp.jar, imap.jar에 있는 모든 클래스 파일을 포함하고 있는 JAR 파일이다. 따라서 간단하게 mail.jar만 CLASSPATH에 추가하면 Java Mail 1.2에서 제공하는 추상 클래스 계층과 POP3, SMTP, IMAP 구현 클래스 계층을 모두 사용할 수 있다.

예제로 사용되는 POP3Checker.java는 일정한 시간 간격으로 POP3 호스트를 검사해서 새로 수신된 메일이 있을 경우 그 메일을 읽어온다. 즉, 간단한 메일 클라이언트라고 생각하면 된다.

POP3Checker의 핵심 부분은 다음과 같다.

   public void process() throws Exception {
      // Session 객체를 구한다.
      java.util.Properties sysProperties = System.getProperties();
      Session session = Session.getDefaultInstance(sysProperties, null);
      session.setDebug(true); // 디버깅 정보를 화면에 보여준다.
      
      // POP3 호스트에 접속한다.
      Store store = session.getStore("pop3");
      store.connect(pop3Host, -1, user, password);
      
      // 기본 폴더를 구한다.
      Folder folder = store.getDefaultFolder();
      if (folder == null)
         throw new NullPointerException("디폴트 메일 폴더 없음");
      
      // "INBOX" 폴더를 구한다.
      folder = folder.getFolder("INBOX");
      if (folder == null)
         throw new NullPointerException("INBOX 폴더를 구할 수 없음");
      
      // 메시지 개수를 구한다.
      folder.open(Folder.READ_WRITE);
      int totalMessages = folder.getMessageCount();
      if (totalMessages == 0)
      {
         System.out.println(folder + "가 비었습니다.");
         folder.close(false);
         store.close();
         return;
      }
      
      // 각 메시지의 속성과 플래그를 구한다.
      Message[] messages = folder.getMessages();
      FetchProfile fp = new FetchProfile();
      fp.add(FetchProfile.Item.ENVELOPE);
      fp.add(FetchProfile.Item.FLAGS);
      fp.add("X-Mailer");
      folder.fetch(messages, fp);
      
      for (int i = 0; i < messages.length; i++)
      {
         if (!messages[i].isSet(Flags.Flag.SEEN)) {
            printMsssage(messages[i]);
         }
         // 읽어온 메시지를 호스트에서 삭제한다.
         messages[i].setFlag(Flags.Flag.DELETED, true); 
      }
      
      folder.close(true);
      store.close();
   }

POP3Checker 클래스는 process() 메소드를 일정 주기 동안 반복적으로 호출한다. POP3Checker.process() 메소드를 살펴보면 다음과 같은 순서로 작업을 진행하는 것을 알 수 있다.

  1. Session 객체 구함
  2. 알맞은 프로토콜을 사용하여 호스트에 접속(Store 객체 사용)
  3. 메일이 저장된 폴더 구함(Folder 객체 사용)
  4. Folder로부터 Message 객체 구함
  5. Message 출력
  6. 읽어온 메시지를 호스트에서 삭제한다.
아웃룩 익스프레스와 같이 일반적으로 널리 사용되는 메일 프로그램들은 모두 1-6번 과정을 거쳐서 메일을 호스트로부터 읽어온다.

위 코드에서 printMessage() 메소드는 파라미터로 전달받은 Message 객체를 화면에 출력해주는 부분으로서 다음과 같다.

   private void printMsssage(Message message) throws Exception {
      String replyTo = null, subject;
      Object content;
      java.util.Date sentDate;
      Address[] a=null;
      
      if ((a = message.getFrom()) != null)
         replyTo = a[0].toString();
      
      subject  = message.getSubject();
      sentDate = message.getSentDate();
      DataHandler dataHandler = message.getDataHandler();
      String contentType = dataHandler.getContentType();
      
      System.out.println("=====================================================");
      System.out.println("보낸사람:"+replyTo);
      System.out.println("보낸시각:"+sentDate);
      System.out.println("주제:"+subject);
      System.out.println("-----------------------------------------------------");
      
      if ( (contentType.indexOf("text/html") != -1) || (contentType.indexOf("text/plain") != -1) ) {
         BufferedReader br = new BufferedReader(new InputStreamReader(dataHandler.getInputStream()));
         char[] buff = new char[512];
         int len;
         while ( (len = br.read(buff)) != -1) {
            System.out.print(new String(buff, 0, len));
         }
         br.close();
      }
      System.out.println("\n=====================================================\n");
   }

printMessage() 메시지에서 실제 메일의 내용은 ContentHandler 객체로부터 추출된다. ContentHandler 클래스는 JAF에 정의되어 있는 클래스로서 다양한 포맷의 데이터를 취급하기 위해서 사용된다. 위 예제에서는 ContentHandler 객체가 처리하고 있는 데이터의 타입이 "text/html"이거나 "text/plain"인 경우에 화면에 출력하도록 하고 있다. POP3Checker.java의 완전한 소스 코드는 관련 링크 부분을 참조하기 바란다.

결론

이 글에서는 Java Mail API가 무엇인지에 대해 개괄적으로 알아보았다. Java Mail API는 모든 메일 시스템에 공통적으로 적용될 수 있는 프레임워크를 제공하고 있기 때문에 별도의 프레임워크 개발없이 손쉽게 새로운 메일 시스템을 구현할 수 있도록 하고 있으며, 뿐만 아니라 널리 사용되고 있는 SMTP나 POP3와 같은 프로토콜에 기반한 메일 시스템 프레임워크를 구현해 놓고 있다. 따라서 개발자들은 특별한 어려움없이 Java Mail API 만을 사용해서 간단하면서도 견고한 메일 시스템을 구축할 수 있게 되었다.

다음 글에서는 웹에서 SMTP를 사용하여 이메일을 전송할 수 있는 간단한 웹기반의 메일 전송 시스템을 구축해 볼 것이다.

관련링크:

+ Recent posts