우와한 개발자

[Python] IMAP으로 Gmail 메일 가져오기 - 메일 검색, 데이터 추출, 첨부파일 다운로드

by 우와한개발자

1. IMAP이란?

  • IMAP(Internet Message Access Protocol)은 서버에서 메일을 가져오는 프로토콜
  • 사용자가 모든 장치에서 이메일에 액세스할 수 있게 해준다.
  • 서버에서 이메일 클라이언트로 이메일을 다운로드하는 대신 이메일 서버와 이메일 클라이언트 간의 중개자 역할을 한다.
  • 즉, 메일을 서버에 보관한 채로 읽기 때문에 여러 기기에서 동기화 가능
  • imaplib은 파이썬 기본 내장 라이브러리라 별도 설치가 필요 없다.

 

2. IMAP으로 Gmail 가져오기

1) 이메일 계정 접속

  • Gmail에서 IMAP을 사용하려면 앱 비밀번호가 필요하다.(일반 비밀번호로는 접속이 안 됨)
import imaplib  

mail = imaplib.IMAP4_SSL('imap.gmail.com')      # Gmail IMAP 서버에 SSL 방식으로 접속
mail.login('your@gmail.com', '앱 비밀번호 16자리')  # 일반 비밀번호 아닌 앱 비밀번호 사용
mail.select('inbox')                            # 받은편지함 선택

print('Connected to mailbox')

 

  • Google 앱 비밀번호 발급 방법
1. Chrome 설정 → Google 계정 관리
2. 보안 및 로그인 → 앱 비밀번호 검색
3. 앱 이름 입력 후 만들기
4. 생성된 16자리 비밀번호 복사해두기 # 생성 후 다시 확인할 수 없으니 반드시 복사

 

  • 폴더 종류
mail.select('inbox')    # 받은편지함
mail.select('Sent')     # 보낸편지함
mail.select('Drafts')   # 임시보관함
mail.select('Trash')    # 휴지통
mail.select('Spam')     # 스팸함

 

2) 메일 검색

  • mail.search()로 조건에 맞는 메일 ID 목록을 가져온다.
# 전체 메일 검색
result, data = mail.search(None, "ALL")
mail_ids = data[0].split()   # 메일 ID 리스트

# 조건 검색
mail.search(None, "UNSEEN")           # 읽지 않은 메일
mail.search(None, "FROM 'test@test.com'")  # 특정 발신자
mail.search(None, "SUBJECT '업무협조'")    # 특정 제목

 

3) 메일 데이터 가져오기

  • 메일 ID로 메일을 가져온 뒤 제목, 발신자, 날짜, 본문을 추출한다.
  • 메일 데이터는 전송 과정에서 다양한 인코딩 방식으로 변환되기 때문에 디코딩이 필요하다.
  • 제목은 이메일 헤더 규격으로 인코딩 → decode_header()
  • 본문은 일반 바이트 데이터 → .decode()
import email
from email.header import decode_header

# 메일 가져오기
result, data = mail.fetch(mail_ids[-1], "(RFC822)")  # 가장 최근 메일
raw_email    = data[0][1]
msg          = email.message_from_bytes(raw_email)

# 제목 디코딩
subject, encoding = decode_header(msg["Subject"])[0]
if isinstance(subject, bytes):
    subject = subject.decode(encoding or "utf-8")

# 발신자, 날짜
sender = msg["From"]
date   = msg["Date"]

print("제목:", subject)
print("발신자:", sender)
print("날짜:", date)

# 본문 텍스트 추출
for part in msg.walk():
    if part.get_content_type() == "text/plain":
        body = part.get_payload(decode=True).decode("utf-8", errors="ignore")
        print("본문:", body[:200])

 

4) 첨부파일 다운로드

  • 메일은 텍스트, 이미지, 첨부파일 등 여러 파트로 구성되어있다.
메일 (msg)
├── 텍스트 본문     (Content-Type: text/plain)
├── HTML 본문      (Content-Type: text/html)
├── 첨부파일1.pdf  (Content-Disposition: attachment)
└── 첨부파일2.xlsx (Content-Disposition: attachment)
  • 각 파트의 Content-Disposition 헤더값이 attachment이면 첨부파일로 판단한다.
  • 파일명도 제목과 마찬가지로 인코딩되어 있어서 decode_header()로 디코딩이 필요하다.
import os

SAVE_DIR = "./downloads"
os.makedirs(SAVE_DIR, exist_ok=True)   # 저장 폴더 없으면 자동 생성

all_files = []

for part in msg.walk():   # 메일의 각 파트 순회
    content_disposition = part.get("Content-Disposition")
		
		# 첨부파일 여부 확인
    if content_disposition and "attachment" in content_disposition:   
        filename = part.get_filename()

        if filename:
            filename, enc = decode_header(filename)[0]   # 파일명 디코딩
            if isinstance(filename, bytes):
                filename = filename.decode(enc or "utf-8")

            filepath = os.path.join(SAVE_DIR, filename)
            with open(filepath, "wb") as f:
                f.write(part.get_payload(decode=True))   # 파일 저장
            print(f"다운로드 완료: {filepath}")
            all_files.append(filepath)

블로그의 정보

우와한개발자 님의 블로그

우와한개발자

활동하기