본문 바로가기
공부기록/자바

[자바] 메일 연동, 메일 읽기(IMAP), 안 읽은 메일만 Fetch하는 법(javax.mail.Folder.search)

by 책읽는 개발자 ami 2021. 3. 19.
728x90
반응형

잡소리

웹에 메일을 연동하는 코드를 짜고 있다.

보내는 건 쉬운데 받아서 제대로 파싱하는 건 신경 쓸 게 뭐이리 많은지..

메일을 가지고 올 때마다 모든 메일을 fetch하면 서버에 무리가 간다.

사용자가 적을 땐 괜찮겠지만 항상 많을 때를 대비하는 것이 프로그래머의 덕..목..

 

코드 설명

아래는 필요한 부분만 가져온 코드다. 출처는 github.com/gujc71/groupware9 입니다.

기본 코드에서 필요한 부분만 약간 수정해서 사용하고 있다.

public class Imap {
  private Folder folder;
  private Message[] msgs;
  
  //안 읽은 메일 개수 반환하는 함수
  public Integer patchMessage(String lastdate) {
      try {
          folder = folder.getFolder(mbox);
          folder.open(Folder.READ_ONLY);
          SearchTerm dateTerm = null;
          if (lastdate!=null) {
              Calendar c = Calendar.getInstance();
              c.set(Calendar.HOUR, 0);
              c.set(Calendar.MINUTE, 0);
              c.set(Calendar.SECOND, 0);
              c.set(Calendar.MILLISECOND, 0);
              c.set(Calendar.AM_PM, Calendar.AM);
              c.add(Calendar.DATE, 1);	// next day
              ReceivedDateTerm endDateTerm = new ReceivedDateTerm(ComparisonTerm.LT, c.getTime());
              c.setTime( Util4calen.str2DateTime(lastdate) );
              ReceivedDateTerm startDateTerm = new ReceivedDateTerm(ComparisonTerm.GE, c.getTime());
              dateTerm = new AndTerm(startDateTerm, endDateTerm);
          }
          if (dateTerm==null) {
              msgs = folder.getMessages();
          }
          else {		    	
              msgs = folder.search(dateTerm);
              FetchProfile fp = new FetchProfile();
              fp.add(FetchProfile.Item.ENVELOPE);
              folder.fetch(msgs, fp);
          }
      } catch (MessagingException e) {
      }
      return msgs.length;
  }
}

 

보통 전체 메일을 읽어올 때는 folder.getMessages() 와 같이 쓴다.

매개변수 lastdate 는 db에서 가장 최신 메일의 시간을 가지고 와 String형 변수다. (yyyy-MM-dd HH:mm:ss 형태)

여기서 최신 메일만 검색하는 부분은 folder.search(dateTerm) 부분이다. 

그리고 ReceivedDateTerm ~ 서부터 네 줄이 가장 중요하다. endDateTerm은 시스템 시간으로 내일 오전0시를, startDateTerm은 lastdate를 저장하여 특정 시간을 지정한다.

예를 들어, new ReceivedDateTerm(ComparisonTerm.LT, 2021-03-18)는 2021-03-18 이전 기간을 의미한다. (두 번째 인자는 Date type) 

따라서 dateTerm에는 db에 저장된 마지막 메일 시간 ~ 다음날 오전 00시 사이의 기간을 의미한다고 보면 된다.

그러므로 folder.search()에 dateTerm이라는 인자를 넣는 것은 "메일박스에서 이 기간동안의 메일만을 가지고 오겠다"는 의미다.

문제는 dateTerm이 시분초까지는 신경쓰지 않는다는 것이다. 그래서 db에 메일을 insert할 때 기존에 있는 메일인지 아닌지 판단하는 로직을 넣어주어야 한다.

마무리 잡소리

처음 프로젝트를 시작할 때, IMAP이니 SMTP니 잘 몰랐다. 이왕 하는 거 알면 좋겠다 싶어서 정리해본다.

post.naver.com/viewer/postView.nhn?volumeNo=26957131&memberNo=2521903

 

이메일 프로토콜 이해하기: SMTP, POP3, IMAP의 의미

[BY 가비아] 다양한 협업툴과 실시간 통신 기술의 발달에도 불구하고 이메일은 여전히 업무의 대부분을 ...

m.post.naver.com

 

위 포스트를 아주아주 짧게 정리한 내용입니다. 세상엔 똑똑한 분이 너무 많아!

SMPT
Simple Mail Transfer Protocol
이메일 '전송' 프로토콜
[1] 클라이언트가 작성한 메일을 서버로 전송할 때
[2] 인터넷을 통해 서버 간 메일을 전송할 때

POP3
Post Office Protocol 3

이메일 '수신' 프로토콜
서버에서 클라이언트 PC로 메일을 직접 다운로드
디폴트: 메일을 다운로드 받으면 서버에서는 메일이 삭제된다.
이러한 특징 때문에 다른 장치에서 동일한 이메일을 확인할 수 없다.

IMAP
Internet Message Access Protocol

이메일 '수신' 프로토콜
서버에 직접 접속하여 메일을 확인하는 방식
처음엔 메일 헤더만 보여주고, 메일을 확인할 때 본문을 보여주는 방식이기 때문에
서버의 통신 트래픽을 높임

용어
헤더: 발신자의 정보, 수신 서버의 호스트 주소, 해당 메일의 고유한 식별자,
        메일이 수신된 날짜 시간 등 정보를 담은 메일의 앞머리 부분
본문: 메일 본문 및 첨부파일을 포함한 실제 메일 내용

728x90
반응형