[python] 네이버 메일 송신/수신 – IMAP/SMTP

이번 글에서는 파이썬으로 네이버 메일을 송신/수신 하는 것을 해보겠습니다.

준비 사항

당연히 메일 송/수신을 하기 위해 네이버 메일이 있어야 하며, 네이버 메일에 로그인 한 뒤 ‘환경설정’ -> ‘POP3/IMAP 설정’ -> ‘IMAP/SMTP 설정’ 에서 IMAP/SMTP을 사용함으로 체크하셔야 합니다.

네이버 메일 IMAP/SMTP 설정

위 이미지에서 파란색 박스에 IMAP과 SMTP에 대한 정보가 적혀있습니다. 자세한 개념은 구글에 검색해보세요.

우리는 SMTP(Simple Mail Transfer Protocol) 정보를 메일 송신할 때 사용할 것이고 , 메일 수신은 IMAP(Internet Message Access Protocol) 정보를 사용할 겁니다. 아래 표의 서버명과 포트를 잘 기억합니다.

 IMAPSMTP
서버명imap.naver.comsmtp.naver.com
포트993587
메일 송신

SMTP를 파이썬에서 사용하기 위해서는 smtplib와 email 라이브러리가 있어야 합니다.
아래 코드는 메일 송신 전체 코드입니다.

# IMAP/SMTP - 송신
import getpass
import smtplib
from email.mime.text import MIMEText

if __name__ == "__main__":
    smtp_name = "smtp.naver.com" # SMTP 서버명
    smtp_port = 587 # SMTP 포트
    
    send_email = "3001ssw@naver.com" # 메일송신에 쓰여질 주소
    send_password = getpass.getpass("비밀번호: ") # 비밀번호
    
    recv_email = "3001ssw@gmail.com" # 수신 메일    
    
    subject = "제목입니다."
    content = "본문입니다."
    
    msg = MIMEText(content)
    msg["Subject"] = subject
    msg["From"] = send_email
    msg["To"] = recv_email
    print(msg.as_string())
    
    smtp = smtplib.SMTP(smtp_name, smtp_port)
    smtp.starttls()
    smtp.login(send_email, send_password)
    
    smtp.sendmail(send_email, recv_email, msg.as_string())
    smtp.quit()

위 코드를 실행하면 gmail에 코드에서 입력한 제목, 본문으로 메일이 온 것을 볼 수 있습니다.
아래는 제 gmail입니다.

메일 수신

이제 메일 수신 하는 것을 해보겠습니다. 우선 먼저 반대로 gmail에서 네이버메일로 메일 하나 보내두겠습니다.

메일 수신에 사용되는 라이브러리는 imaplib와 email 입니다.

아래와 같이 수신 코드를 짜줍니다.

# IMAP/SMTP - 수신
import imaplib
import email
from email.header import decode_header, make_header
from getpass import getpass    

if __name__ == "__main__":
    imap_server = 'imap.naver.com' # 서버명
    imap_port = 993 # 포트
    
    email_id = '3001ssw@naver.com' # 수신 확인할 이메일
    email_password = getpass() # 메일 패스워드

    try:
        # IMAP 접속        
        imap = imaplib.IMAP4_SSL(imap_server, imap_port)

        # 로그인
        imap.login(email_id, email_password)

        # 받은 편지함
        imap.select()

        # 받은 편지함 내의 모든 메일 검색
        resp, data = imap.search(None, 'ALL')
        # 받은 편지함 내의 안본 메일 검색
        # resp, data = session.search(None, 'UNSEEN')

        data_byte:bytes = data[0] # data = [b'1 2 3 4 ... ']
        search_mail = data_byte.split() # 검색한 모든 메일 - 바이너리 데이터 쪼개기
        print("search mail count:", len(search_mail))
        
        last_mail = search_mail[-1] # 마지막 메일
        
        result, data = imap.fetch(last_mail, '(RFC822)') # RFC822=전자메일 표준

        #사람이 읽기 힘든 Raw 메세지 (byte)
        raw_email = data[0][1]

        #메시지 처리(email 모듈 활용)    
        email_msg = email.message_from_bytes(raw_email)
        mail_from = make_header(decode_header(email_msg.get('From'))) # From
        mail_to = make_header(decode_header(email_msg.get('To'))) # To
        mail_date = make_header(decode_header(email_msg.get('Date'))) # Date
        mail_subject = make_header(decode_header(email_msg.get('Subject'))) # Subject
        
        # Content
        mail_content = None
        for part in email_msg.walk():
            charset = part.get_content_charset()
            ctype = part.get_content_type()
            
            if ctype == 'text/plain':
                mail_content = part.get_payload(decode=True)  # decode
                break
            elif ctype == 'text/html':
                # Content-Disposition는 http response body의 컨텐츠 성향?기질?인데, attachment는 파일이 첨부되어있는것
                cdispo = str(part.get('Content-Disposition'))
                if 'attachment' not in cdispo:
                    mail_content = part.get_payload(decode=True)
                else:
                    mail_content = ""
                break
            else:
                mail_content = ""
        
        if type(mail_content) is bytes and charset is not None:
            mail_content = mail_content.decode(charset)
            if ctype == 'text/html':
                    from bs4 import BeautifulSoup
                    soup = BeautifulSoup(mail_content, 'html.parser')
                    mail_content = soup.get_text()
		
        # 메일 출력
        print(str(mail_from))
        print(str(mail_to))
        print(str(mail_date))
        print(str(mail_subject))
        print(str(mail_content))
        
        # Log out
        imap.logout()
        
    except Exception as e:
        print(e)

위 코드를 수행하면 아래와 같은 출력 화면이 나옵니다.

송신과 다르게, 수신된 메일을 읽어올 때 주의해야할 점은 메일의 본문(Content) 부분입니다.
보통 메일은 텍스트만 온다고 생각할 수 있는데 html 형식으로 오는 경우도 있습니다.

위 코드에서 Content 부분에 ctype에 입력된 값, ‘text/plain’과 ‘text/html’로 경우를 분리해주었고 html인 경우 BeautifulSoup로 텍스트만 추출하였습니다.

위 코드에 최대한 상세하게 주석을 달았으며, 전체 메일 읽어오는 방법도 조금만 해보시면 하실 수 있습니다.

이상으로 python으로 메일 송/수신에 대해 알아보았습니다.

참고 사이트

사이트 1
사이트 2