EJB(xml/mail/jms/jdbc)
2018.04.02 / 02:47

JavaMail API를 이용한 메일 가져오기

인사이드자바
추천 수 13

JavaMail API를 이용한 메일 가져오기

http://kwaknu.egloos.com/4989978

JDC Tech Tip "Sending Mail With the JavaMail API에서는 JavaMail API를 이용한 SMTP를 통해 메일을 보내는 방법을 보여준다. 이 팁은 POP / IMAP 서버에서 메일을 가져오는 방법을 보여줄 것이다.

메일을 가져오는 것은 메일을 보내는 것과 비슷하다. 예를 들면, 메일을 보낼 때는 Session, Message, Address, Transport 클래스를 사용한다. 메일을 가져올 때도 같은 Session, Message 클래스를 사용하지만, Folder와 Store 클래스를 사용할 수도 있다. 메일을 가져오려면 메일서버에 접속하고 메시지는 Store의 Folder에 저장이 된다.

메일을 가져오기 위하여 처음 할 일은 메일서버와 연결을 하는 것인데, 메일을 보낼 때와 같은 방법이다. 그러나 접속하는 메일서버는 다르다. 메일을 보낼 때는 SMTP(Simple Mail Transfer Protocol)를 지원하는 서버에 연결해야 합니다. SMTP는 메일을 보내기 위한 프로토콜입니다. 메일을 가져오기 위해서는 POP3(Post Office Protocol, Version 3)나 IMAP4(Internet Message Access Protocol, Version 4)를 지원하는 서버에 연결해야 한다. 이들 프로토콜은 메일을 가져오기 위해 설계되었다. POP3는 단순한 프로토콜이다. 메일을 가져올 수만 있고 새로운 메일을 구별할 수 있는 기능은 없다. 그에 비해 IMAP은 상당히 복잡하다.

Session 클래스의 getDefaultInstance()나 getInstance() 메소드를 호출해서 메일 세션을 가져올 수 있다. getDefaultInstance() 메소드를 호출하면 공유 세션 인스턴스가 반환된다. 즉, 메소드를 호출할 때마다 동일한 세션이 반환된다. 반면에 getInstance() 메소드를 호출하면 그때마다 새로운 세션 인스턴스가 반환된다. 새로운 세션은 다른 쓰레드가 동시에 공유세션과 작업하기를 위하지 않을 때 사용하면 유용하다.

세션을 얻을 때 Properties 인스턴스를 메소드 인수로 넘겨야 한다. 이것은 연결하고자 하는 메일서버의 속성을 가지고 있다. 연결하고자 하는 메일서버로 "mail.pop3.host" (또는 "mail.imap.host")를 지정해야 한다.(예, pop.example.com)
  // Setup properties
Properties props = System.getProperties();
props.put("mail.pop3.host", host);




메일을 가져올 때 연결을 위한 인증과정을 거쳐야 한다. 예를 들어 사용자이름과 패스워드를 입력해야 한다. JavaMail의 Authenticator 클래스를 확장해서 사용하면 된다. 예로 PopupAuthenticator 클래스는 사용자이름과 패스워드를 입력하기 위해서 Swing의 JOptionPane를 사용하고 있다. 이 예제는 사용자가 콤마로 구분된 사용자이름과 패스워드를 입력하게 되어 있다. getPasswordAuthentication() 메소드는 사용자이름과 패스워드를 반환하고 있다.(패스워드 입력을 위해 JPasswordField를 사용해 보자)

import javax.mail.*;
import javax.swing.*;
import java.util.*;

public class PopupAuthenticator 
    extends Authenticator {

  public PasswordAuthentication 
      getPasswordAuthentication() {
    String username, password;

    String result = JOptionPane.showInputDialog(
      "Enter 'username,password'");

    StringTokenizer st = 
      new StringTokenizer(result, ",");
    username = st.nextToken();
    password = st.nextToken();

    return new PasswordAuthentication(
      username, password);
  }
}



Properties와 Authenticator를 생성한 이후 세션을 얻어 올 수 있다.

// Setup authentication, get session
Authenticator auth = new PopupAuthenticator();
Session session = 
  Session.getDefaultInstance(props, auth);



다음으로 getStore() 메소드를 호출해서 Store에 연결할 수 있는데, 이때 "pop3"나 "imap"과 같이 프로토콜 이름을 인수로 넘겨야 한다. 다음은 POP3 서버에 연결하는 방법을 보여준다.

// Get the store
Store store = session.getStore("pop3");
store.connect();


Store의 connect() 메소드는 PopupAuthenticator를 호출하게 된다. 위해서 언급했듯이 PopupAuthenticator는 사용자이름과 패스워드를 입력받는다. 만일 사용자이름과 패스워드가 메일계정과 일치하면 메일서버와 연결이 되고 메일을 읽을 수 있다. 모든 메일은 Folder 인스턴스에 저장이 되는데 메일을 읽기 위해서 먼저 Folder와 연결해야 한다. POP 메일일 경우엔 오직 한개의 INBOX라는 Folder가 있다. 그리고, IMAP경우에는 INBOX나 사용자가 만든 Folder가 존재한다. 만일 INBOX에서 메일을 읽으려면 Store의 getFolder() 메소드를 호출해서 Folder와 연결하면 된다.
 

// Get folder
Folder folder = store.getFolder("INBOX");


다음으로 open() 메소드를 이용해서 Folder를 연다. Folder를 열 때에는 Folder.READ_WRITE나 Folder.READ_ONLY 모드로 열 수 있다. 메일을 읽기만 할 때는 Folder.READ_ONLY로, 삭제를 하고 싶으면 Folder.READ_WRITE 열면 된다.
 

folder.open(Folder.READ_ONLY);


Folder에 연결되면 개개의 Message 객체에 접근할 수 있다. getMessage() 메소드를 호출함으로써 개개의 Message에 접근할 수 있다. 다음은 getMessage() 메소드를 이용해서 모든 Message에 가져오는 예제이다.
 

// Get directory
Message message[] = folder.getMessages();


Folder 클래스의 getNewMessageCount() 메소드는 Folder의 새로운 메시지 수를 반환하다. 그러나, POP 서버를 사용할 경우에는 이것을 사용할 수 없다. POP에서는 새로운 Message 개념을 지원하지 않는다는 것을 기억하자. Message를 가져올 때 몇 가지 옵션이 있다. 예를 들어 getFrom()은 보낸사람의 메일주소, getSubject()는 메일을 제목을 가져올 수 있다.
 

// Display from (only first) and subject of messages
for (int i=0, n=message.length; i<n; i++) {
  System.out.println(i + ": " 
    + message[i].getFrom()[0] 
    + "\t" + message[i].getSubject());
}


만일 메시지 내용을 보려면 getContent() 메소드를 사용하면 된다.
  System.out.println(message[i].getContent());


또한, writeTo() 메소드를 이용해서 헤더를 포함한 Message 내용을 스트림으로 저장할 수 있다. 메일을 읽은 후에 Folder와 Store는 반드시 닫아야한다. Folder의 경우에는 close()를 호출할 때 Message를 지울지 안 지울지를 인수롤 넘겨야 하고, Store의 close()는 인수가 필요없다.
  // Close connection 
folder.close(false);
store.close();


다음은 Fetch 프로그램 코드로 위에서 설명한 메일을 가져오는 예제이다. 이 프로그램을 실행시키기 위해서는 JavaMail API가 설치되어 있어야 하며, 또한 JavaBeansTM Activation Framework도 설치해야 한다. 다운로드 정보는 아래에 있다. Fetch 프로그램은 INBOX에 저장되어 있는 메시지의 최초 200자의 문자를 출력합니다. 만일 메일 서버가 POP을 지원하지 않고, IMAP을 지원하면 코드에서 "pop"을 "imap"으로 바꾸면 된다. 프로그램을 컴파일하기 전에 위에서 소개한 PopupAuthenticator를 먼저 컴파일하자. 커맨드라인에서 다음과 같이 Fetch 프로그램을 실행하자.
 

java Fetch mailserver


메일서버의 이름은 당신의 메일서버 이름으로 바꾸자. 실행시킨 후 사용자이름과 패스워드를 입력해야 한다.
 

import java.io.*;
import java.util.Properties;
import javax.mail.*;
import javax.mail.internet.*;

public class Fetch {
  public static void main (String args[]) 
      throws Exception {
    String host = args[0];

    // Get system properties
    Properties props = System.getProperties();
    props.put("mail.pop3.host", host);

    // Setup authentication, get session
    Authenticator auth = new PopupAuthenticator();
    Session session = 
      Session.getDefaultInstance(props, auth);

    // Get the store
    Store store = session.getStore("pop3");
    store.connect();

    // Get folder
    Folder folder = store.getFolder("INBOX");
    folder.open(Folder.READ_ONLY);

    // Get directory
    Message message[] = folder.getMessages();
    for (int i=0, n=message.length; i<n; i++) {

       System.out.println(i + ": " 
         + message[i].getFrom()[0] 
         + "\t" + message[i].getSubject());
       String content = 
         message[i].getContent().toString();
       if (content.length() > 200) {
         content = content.substring(0, 200);
       }
       System.out.print(content);
    }

    // Close connection 
    folder.close(false);
    store.close();
    System.exit(0);
  }
}


최신버전의 JavaMail API를 JavaMail API page에서 다운받을 수 있다. JavaMail API를 사용하기 위해서는 JavaBeans Activation Framework이 설치되어 있어야 한다. JavaBeans Activation Framework은 JavaBeans Activation Framework page에서 다운받을 수 있다. 또한, 이들은 Java 2 Platform, Enterprise Edition 1.3 download에서 구할 수 있다. JavaMail 소스코드는 J2EE 1.3 Sun Community Source Licensing (SCSL) program에서 구할 수 있다. 다음 코드는 이전 코드에서 약간 변경된 것이다. 만일 Authenticator를 사용하지 않으려면 Properties 지정되지 않은 Session을 얻으면 된다. 그리고 호스트이름, 사용자이름, 패스워드를 인수로 해서 connect() 메소드를 호출하자. 다음은 변경된 코드의 일부이다.
  // Setup empty properties
Properties props = new Properties();

// Get session
Session session = Session.getDefaultInstance(props, null);

// Get the store
Store store = session.getStore("pop3");
store.connect(host, username, password);