ai-creator

[Python] 업무 자동화 - Naver 메일 보내기 본문

오늘 배워 오늘 쓰는 OpenAPI/Quick Start

[Python] 업무 자동화 - Naver 메일 보내기

ai-creator 2020. 6. 12. 20:06
반응형

오.오.쓰 에 오신 것을 환영합니다.

[이메일 자동 전송 프로젝트] 입니다.

아래와 같은 순서로 배워보겠습니다.

 

1. 학습 목표

2. 사전 준비

3. 사전 지식 쌓기

4. 구현

5. 요약정리

 


1. 학습 목표

회사 생활에 권태기가 오는 이유 중에 1위가 ‘반복되는 업무에 대한 지루함’이 이라고 합니다. 무려 58.2%(복수응답)가 답했다고 해요. (출처 : http://www.thejobnews.kr) 직장인들에게는 보고서와 메일을 쓰는데 많은 시간을 할애하게 되죠. 두가지 업무는 반복적이고 지루한 일입니다. 두 업무만 해결이 되어도 더 가치있는 일을 하거나, 칼퇴를 할 수 있을텐데 말이죠.

 

보고서의 경우는 '4장. 보고서 자동화 프로젝트'를 통해서 반복적인 업무를 프로그램에게 맡겼습니다.

메일은 어떻게 하면 업무 효율을 높일 수 있을까요? 

필자의 경우는 서명이나 서식을 작성해 두어 업무 효율을 높였습니다. 이 정도의 메일 서식을 넣어두어도 반복적인 업무를 줄일 수 있었습니다.

[그림 1] 업무 효율을 높이는 메일 서명 예시

 

그런데, 만약에 파이썬을 통해 메일을 자동으로 보낼 수 있다면 어떨까요? 상상만 해도 너무 즐겁습니다.

이번 장에서는 파이썬으로 네이버 이메일 보내는 법을 학습해보겠습니다. 한국인들이 많이 사용하는 네이버 메일을 기준으로 설명하였으며, 동작 방법은 비슷하므로 다른 메일에도 활용할 수 있습니다.

 

2가지 종류의 이메일을 보내보겠습니다.

텍스트만 구성된 메일과 파일이 첨부된 메일입니다.

 

[그림 2] 텍스트 메일 전송 결과 / [그림 3] 텍스트 및 파일이 첨부된 메일 전송 결과

 

첨부파일도 보낼 수 있으니, 만약 주식 또는 트렌드 분석처럼 주기적으로 받고 싶은 메일이 있다면 같이 연동해서 활용할 수 있습니다.

 

[언어 & 환경(IDE)]

Python 3.7 & Jupter notebook

 

[프로젝트 리소스 및 소스 코드]

email_sending.ipynb : 네이버 메일 보내기 구현 코드

- res/email_sending: 네이버 메일 보내기 리스소 파일

 

> 접속 URL :  drive.google.com/drive/folders/10KXyPrJ_KEesvAvjnMpx1DS_md7gaN6H?usp=sharing

 

ai-creator 공유폴더 - Google 드라이브

 

drive.google.com

※ 프로젝트에 필요한 리소스 및 소스코드의 경로 구성은 자유롭게 설정하면 됩니다. 그러나, 아래 설명되어 있는 코드 구현이 제시된 구성으로 되어 있으니, 동일하게 경로와 파일명으로 구성해 둔다면 별다른 코드 수정 없이 실행해 볼 수 있습니다.

 

2. 사전 준비

메일 자동화 프로젝트를 위해 두 가지 사전 준비가 필요합니다

첫째, 라이브러리 설치

둘째, 수신 메일 IMAP 설정

입니다.

 

다음과 같은 순서로 진행해보겠습니다.

2-1)  라이브러리 

2-2) 수신 메일 IMAP 설정

 

2-1)  라이브러리 

메일 자동화를 위해 두가지 라이브러리를 사용합니다. smtplib과 email 라이브러리 입니다.

smtplib 라이브러리는 이메일 전송을 위해 필요합니다. 파이썬 설치시 기본으로 설치된 라이브러리이므로, 별도의 설치는 필요없습니다. 

> 링크 (smtplib 라이브러리 문서) : docs.python.org/ko/3/library/smtplib.html

 

email 라이브러리 또한 기본 라이브러리로 별도의 설치는 필요 없습니다. 이메일 메시지를 관리하며, 한글 또는 파일을 첨부하여 메시지를 보낼 때 편리합니다.

> 링크 (email 라이브러리 문서) : docs.python.org/ko/3/library/email.html

 

 

2-2) 발신(send) 메일 SMTP 설정 

네이버 이메일 계정을 준비합니다. 수신, 발신용 2개의 이메일 주소를 권장하지만, 1개의 이메일이 있어도 상관없습니다. 계정이 2개인 경우는 수신/송신 에 대한 이해를 좀 더 쉽게 할 수 있는 장점이 있습니다.  

 

발신(send)용 메일 계정에 SMTP를 '사용'으로 설정합니다. 

순서 : [환경설정] 버튼 클릭  > [POP3/IMAP 설정] 버튼 클릭  > [IMAP/SMTP설정] 탭 클릭 > [사용함] 선택 > [확인] 버튼 클릭

[그림 4] SMTP 설정

POP3와 IMAP은 메일을 받을 때(수신, receive)의 프로토콜이며, SMTP(Simple Mail Transfer Protocol)는 메일을 보낼 때(발신, send)의 프로토콜입니다. 

 

설정 후 코딩에 사용할 내용은 6번, 7번에 해당되는 내용입니다.

- SMTP 서버명 : smtp.naver.com

- SMTP 포트 : 587, 보안 연결(TLS) 필요

 

 

3. 사전 지식 쌓기

 

지식을 쌓을 내용은 다음과 같습니다. 

3-1) 이메일 전송 흐름

3-2) 메일 내용 작성 및 파일 첨부 하기

 

3-1) 이메일 전송 흐름

[그림 5]  이메일 전송 흐름 (출처 : http://blog.naver.com/PostView.nhn?blogId=lsh00124&logNo=220533056400)

SMTP는 Simple Mail Transfer Protocol의 약자 
POP3는  Post Office Protocol의 약자 
IMAP은 Internet Message Access Protocol약자 입니다. 
모두 Protocol이라는 단어로 끝납니다. Protocol이란, 통신에 있어 상호간에 약속한 '규약'입니다.
규약에 맞춰 서버들이 통신을 하고, 목적에 맞게 동작한다고 생각하면 됩니다. 

즉, 편지를 쓰면 우체국에 모았다가 받는 사람의 우체국을 통해 개개인에게 전달 되듯, 인터넷 상에서도 우체국 역할을 해주는 '서버'가 있습니다. SMTP/POP3/IMAP서버가 바로 그 역할을 합니다.  
이메일을 보내면 SMTP 서버(우체국 역할)에 저장하고, 받을 사람의 POP3서버나 IMAP서버(우체국 역할)로 보내지게 됩니다. 이 흐름과 규약에 맞춰 메일을 주고 받을 수 있게 됩니다.

 

그럼 이제 이메일을 보내는 작업을 프로그램화 한다고 생각해봅시다. 메일을 보내기 위해 여러분이 하는 행동을 잘 생각해보세요. 

[그림 6] 이메일 전송 순서

첫번째, 발신자의 계정으로 로그인을 합니다. id와 password를 이용하죠.

두번째, 메일을 작성합니다. 

세번째, '보내기' 버튼을 눌러 메일 보내기를 '요청' 합니다.

그럼 뒷단에서는 SMTP 프로토콜과 POP3/IMAP 프로토콜을 이용하여 각 서버들이 통신을 거처 수신자의 계정으로 메일이 도착하게 됩니다.

 

이를 그대로 코드로 옮겨 보겠습니다.

 

코드

import smtplib

smtp_info = dict({"smtp_server" : "smtp.naver.com", # SMTP 서버 주소
                  "smtp_user_id" : "<송신자(sender) 메일 계정>@naver.com", 
                  "smtp_user_pw" : "<송신자(sender) 메일 패스워드>" ,
                  "smtp_port" : 587}) # SMTP 서버 포트
                  
def send_email(smtp_info, msg):
    with smtplib.SMTP(smtp_info["smtp_server"], smtp_info["smtp_port"]) as server:
        # TLS 보안 연결
        server.starttls() 
        # 로그인
        server.login(smtp_info["smtp_user_id"], smtp_info["smtp_user_pw"])

        # 로그인 된 서버에 이메일 전송
        response = server.sendmail(msg['from'], msg['to'], msg.as_string()) # 메시지를 보낼때는 .as_string() 메소드를 사용해서 문자열로 바꿔줍니다.

        # 이메일을 성공적으로 보내면 결과는 {}
        if not response:
            print('이메일을 성공적으로 보냈습니다.')
        else:
            print(response)

코드 설명

1라인 : 이메일 전송을 위한 smtplib 라이브러리를 import합니다. 

3~6라인 : 전송(send)을 위한 정보입니다. smtp_server는 보내질 서버로 [그림 4]의 6번에 해당합니다. smtp_user_id는 보낼 사람의 메일 id이며, smtp_user_pw는 password입니다. 이 두 정보는 이후 로그인을 할 때 사용합니다. smtp_port는  [그림 4]의 7번에 해당합니다.

8~22라인 : 메일 전송을 위한 함수입니다. 발신자의 정보(smtp_info)와 수신자정보와 보낼 메시지를 담은 정보(msg)를 입력으로 받습니다. SMTP 서버를 연결하고, TLS 보안을 사용하는 포트이므로 ([그림 4] 참고) 이므로 TLS 보안을 연결합니다. 13라인은 발신자 계정으로 로그인을 하고, 16라인은 메시지를 전송하게 됩니다.

 

※ "Step2)  텍스트로만 구성된 이메일 보내기"에서 이메일을 보내보세요.

 

실제 메일을 보내는 순서와 프로그램이 유사하죠?

 

3-2) 메일 내용 작성 및 파일 첨부 하기

메일 내용을 작성 할 때, 간단하게 text로만 구성을 할 수도 있지만, 파일을 첨부할 수도 있습니다.

email 라이브러리를 사용하여, 쉽게 작업을 할 수 있습니다.

> 링크 (email 라이브러리 문서) : docs.python.org/ko/3/library/email.html

> 링크 (email 라이브러리 quick-start) : docs.python.org/ko/3.4/library/email-examples.html

 

email 라이브러리를 통해 다양한 종류의 메일을 보낼 수 있습니다. html 로 구성된 메일, 파일 첨부등을 할 수 있습니다.

이 장에서는 text로 구성된 메일 및 파일 첨부 하는 방법에 대해서만 학습하도록 하겠습니다.

 

text로 구성된 메일을 보낼 경우는 MIMEText 함수를 사용하면 됩니다.

image를 보낼 경우는 MIMEImage 함수, audio를 보내고 싶다면 MIMEAudio 함수를, 그외의 MIMEBase 함수를 호출합니다. 즉, 보내고자 하는 media의 종류에 따라 호출하는 함수가 다릅니다.

또한 다양한 종류의 메시지를 한번에 보내고 싶을 경우 MIMEMultipart 함수를 사용해서 각 객체를 추가하면 됩니다.

 

코드

# 이메일 메시지에 다양한 형식을 중첩하여 담기 위한 객체
from email.mime.multipart import MIMEMultipart

# 이메일 메시지를 이진 데이터로 바꿔주는 인코더
from email import encoders

# 텍스트 형식
from email.mime.text import MIMEText
# 이미지 형식
from email.mime.image import MIMEImage
# 오디오 형식
from email.mime.audio import MIMEAudio

# 위의 모든 객체들을 생성할 수 있는 기본 객체
# MIMEBase(_maintype, _subtype)
# MIMEBase(<메인 타입>, <서브 타입>)
from email.mime.base import MIMEBase

msg_dict = {
  'text' : {'maintype' : 'text', 'subtype' :'plain', 'filename' : 'test.txt'}, # 텍스트 첨부파일
  'image' : {'maintype' : 'image', 'subtype' :'jpg', 'filename' : 'test.jpg' }, # 이미지 첨부파일
  'audio' : {'maintype' : 'audio', 'subtype' :'mp3', 'filename' : 'test.mp3' }, # 오디오 첨부파일
  'video' : {'maintype' : 'video', 'subtype' :'mp4', 'filename' : 'test.mp4' }, # 비디오 첨부파일
  'application' : {'maintype' : 'application', 'subtype' : 'octect-stream', 'filename' : 'test.pdf'} # 그외 첨부파일
}

def make_multimsg(msg_dict):
    multi = MIMEMultipart(_subtype='mixed')
    
    for key, value in msg_dict.items():
        # 각 타입에 적절한 MIMExxx()함수를 호출하여 msg 객체를 생성한다.
        if key == 'text':
            with open(value['filename'], encoding='utf-8') as fp:
                msg = MIMEText(fp.read(), _subtype=value['subtype'])
        elif key == 'image':
            with open(value['filename'], 'rb') as fp:
                msg = MIMEImage(fp.read(), _subtype=value['subtype'])
        elif key == 'audio':
            with open(value['filename'], 'rb') as fp:
                msg = MIMEAudio(fp.read(), _subtype=value['subtype'])
        else:
            with open(value['filename'], 'rb') as fp:
                msg = MIMEBase(value['maintype'],  _subtype=value['subtype'])
                msg.set_payload(fp.read())
                encoders.encode_base64(msg)
        # 파일 이름을 첨부파일 제목으로 추가
        msg.add_header('Content-Disposition', 'attachment', filename=value['filename'])

        # 첨부파일 추가
        multi.attach(msg)
    
    return multi

코드 설명

1~17라인 : 필요한 라이브러리를 import합니다. 

19~25라인 : 추가할 메시지에 대한 정보를 담습니다. key에는 media type을 의미하고, value에는 maintype, subtype, filename 정보를 담습니다. 첨부 파일을 없애고 싶다면, 빼고 싶은 라인에 주석표시(#)를 하고, 추가하고 싶다면 라인을 추가하여 쉽고, 편하게 첨부 파일을 관리하도록 구현하였습니다.

27~52라인 : 다양한 종류의 메시지를 추가해주는 함수입니다. 메시지의 정보를 담은 msg_dict를 입력으로 받습니다. msg_dict는 key와 value로 이루어져 있습니다. key에 해당하는 media type별로 적절한 함수를 호출해줍니다. msg_dict가 여러개인 경우, 반복문으로 반복 수행하고 42라인처럼 attach함수를 통해 객체를 추가합니다.

4. 구현

이번장에서는 두가지 종류의 이메일을 보내보겠습니다.

텍스트로만 구성된 이메일과 다양한 종류의 첨부파일이 있는 이메일입니다.

 

[코드 파일]

- email_sending.ipynb

 

[구현 순서]

점진적으로 구현을 완성해 갈 수 있도록 Step1 > Step2, Step3 순서로 진행되며, 목적에 맞게 Step2와 Step3을 사용하세요.

Step1 이메일 전송 함수 만들기
 Step2 텍스트로만 구성된 이메일 보내기
Step3 텍스트와 다양한 종류의 파일이 첨부된 이메일 보내기

Step1) 이메일 전송 함수 만들기

코드

import smtplib
# 이메일 메시지에 다양한 형식을 중첩하여 담기 위한 객체
from email.mime.multipart import MIMEMultipart

# 이메일 메시지를 이진 데이터로 바꿔주는 인코더
from email import encoders

# 텍스트 형식
from email.mime.text import MIMEText
# 이미지 형식
from email.mime.image import MIMEImage
# 오디오 형식
from email.mime.audio import MIMEAudio

# 위의 모든 객체들을 생성할 수 있는 기본 객체
# MIMEBase(_maintype, _subtype)
# MIMEBase(<메인 타입>, <서브 타입>)
from email.mime.base import MIMEBase
                  
def send_email(smtp_info, msg):
    with smtplib.SMTP(smtp_info["smtp_server"], smtp_info["smtp_port"]) as server:
        # TLS 보안 연결
        server.starttls() 
        # 로그인
        server.login(smtp_info["smtp_user_id"], smtp_info["smtp_user_pw"])

        # 로그인 된 서버에 이메일 전송
        response = server.sendmail(msg['from'], msg['to'], msg.as_string()) # 메시지를 보낼때는 .as_string() 메소드를 사용해서 문자열로 바꿔줍니다.

        # 이메일을 성공적으로 보내면 결과는 {}
        if not response:
            print('이메일을 성공적으로 보냈습니다.')
        else:
            print(response)
            
def make_multimsg(msg_dict):
    multi = MIMEMultipart(_subtype='mixed')
    
    for key, value in msg_dict.items():
        # 각 타입에 적절한 MIMExxx()함수를 호출하여 msg 객체를 생성한다.
        if key == 'text':
            with open(value['filename'], encoding='utf-8') as fp:
                msg = MIMEText(fp.read(), _subtype=value['subtype'])
        elif key == 'image':
            with open(value['filename'], 'rb') as fp:
                msg = MIMEImage(fp.read(), _subtype=value['subtype'])
        elif key == 'audio':
            with open(value['filename'], 'rb') as fp:
                msg = MIMEAudio(fp.read(), _subtype=value['subtype'])
        else:
            with open(value['filename'], 'rb') as fp:
                msg = MIMEBase(value['maintype'],  _subtype=value['subtype'])
                msg.set_payload(fp.read())
                encoders.encode_base64(msg)
        # 파일 이름을 첨부파일 제목으로 추가
        msg.add_header('Content-Disposition', 'attachment', filename=value['filename'])

        # 첨부파일 추가
        multi.attach(msg)
    
    return multi

 

코드 설명

'3. 사전 학습 쌓기' 에서 구현한 함수입니다. 자세한 설명은 해당 챕터에서 확인하세요.

 

Step2)  텍스트로만 구성된 이메일 보내기

 

제목과 내용으로만 구성된 이메일을 보내보겠습니다.

 

코드

from email.mime.text import MIMEText

smtp_info = dict({"smtp_server" : "smtp.naver.com", # SMTP 서버 주소
                  "smtp_user_id" : "<송신자(sender) 메일 계정>@naver.com", 
                  "smtp_user_pw" : "<송신자(sender) 메일 패스워드>", 
                  "smtp_port" : 587}) # SMTP 서버 포트

# 메일 내용 작성
title = "기본 이메일 입니다."
content = "메일 내용입니다."
sender = "<송신자(sender) 메일 계정>@naver.com"
receiver = "<수신자(receiver) 메일 주소>@naver.com" 

# 메일 객체 생성 : 메시지 내용에는 한글이 들어가기 때문에 한글을 지원하는 문자 체계인 UTF-8을 명시해줍니다.
msg = MIMEText(_text = content, _charset = "utf-8") # 메일 내용

msg['Subject'] = title     # 메일 제목
msg['From'] = sender       # 송신자
msg['To'] = receiver       # 수신자


send_email(smtp_info, msg )

 

실행 결과

 

코드 설명

1~6 라인 : '3. 사전 지식 쌓기'를 참고하세요.

9~12라인 : 이메일 내용을 작성에 필요한 정보입니다. 제목, 내용, 송신자, 수신자가 필요합니다.

15라인 : text로만 구성된 이메일을 보냄으로 MIMEText 함수로 객체를 생성합니다.

17~19라인 : 생성된 객체에 제목, 송신자, 수신자 정보를 추가해줍니다.

22라인 : 이메일 전송을 요청합니다.

 

Step3) 텍스트와 다양한 종류의 파일이 첨부된 이메일 보내기

제목, 내용뿐만 아니라 첨부파일이 있는 이메일을 보내보겠습니다.

 

코드

smtp_info = dict({"smtp_server" : "smtp.naver.com", # SMTP 서버 주소
                  "smtp_user_id" : "<송신자(sender) 메일 계정>@naver.com" 
                  "smtp_user_pw" : "<송신자(sender) 메일 패스워드>" 
                  "smtp_port" : 587}) # SMTP 서버 포트

msg_dict = {
  'text' : {'maintype' : 'text', 'subtype' :'plain', 'filename' : 'test.txt'}, # 텍스트 첨부파일
  'image' : {'maintype' : 'image', 'subtype' :'jpg', 'filename' : 'test.jpg' }, # 이미지 첨부파일
  'audio' : {'maintype' : 'audio', 'subtype' :'mp3', 'filename' : 'test.mp3' }, # 오디오 첨부파일
  'video' : {'maintype' : 'video', 'subtype' :'mp4', 'filename' : 'test.mp4' }, # 비디오 첨부파일
  'application' : {'maintype' : 'application', 'subtype' : 'octect-stream', 'filename' : 'test.pdf'} # 그외 첨부파일
}

#####################
# 메일 내용 작성
#####################
title = "첨부파일이 있는 이메일입니다."
content = "메일 내용입니다."
sender = "<송신자(sender) 메일 계정>@naver.com"
receiver =  "<수신자(receiver) 메일 주소>@naver.com" 

# 메일 내용
msg = MIMEText(_text = content, _charset = "utf-8") 

# 첨부파일 추가
multi = make_multimsg(attach_dict)
multi['subject'] = title  
multi['from'] = sender  
multi['to'] = receiver     
multi.attach(msg)

# 첨부파일이 추가된 이메일 전송
send_email(smtp_info, multi )

 

실행 결과

 

 

코드 설명

1~12 라인 : '3. 사전 지식 쌓기'를 참고하세요.

16~19라인 : 메일 내용을 작성에 필요한 정보입니다. 제목, 내용, 송신자, 수신자가 필요합니다.

22라인 : text로만 구성된 객체를 만들기 위해 MIMEText 함수를 호출합니다.

26라인 : 다양한 첨부파일에 대해서 객체를 만듭니다.

27~30라인 : 생성된 객체에 제목, 송신자, 수신자 정보를 추가해주고, text객체와 첨부파일 객체를 attach함수를 통해 붙여줍니다.

33라인 : 이메일 전송을 요청합니다.

 

5. 요약정리

이번 장에서는 이메일 자동 전송 프로젝트를 진행해 보았습니다.이메일 전송 흐름에 대해 이해 했습니다. 이메일 전송방법을 프로그램으로 작성할 때, 이제까지 이메일을 보낸 흐름과 동일하다는 점을 알게 되었습니다. 로그인 -> 메일 작성 -> 보내기 요청 순서로 말이죠. smtplib과 email 두가지 라이브러리를 사용하여,  텍스트로만 작성된 이메일, 다양한 첨부파일이 추가된 이메일을 보내보았습니다.

 

이메일 자동 전송 프로젝트의 학습을 마치셨다면, 주식분석 자동화 프로젝트를 하실 수 있습니다.  주식 뿐만이 아니라,  크롤링을 통해 분야별 트렌드를 모아 주기적으로 이메일로 전송해 보는건 어떨까요?

 

 

ㅁ trouble shooting

import socket
socket.gethostname()

출력된 결과에 한글이 있다면, 컴퓨터 이름을 모두 영어로 변경할 것

> 변경 방법 : 내 PC > 오른쪽마우스 > 설정 > 컴퓨터 이름, 도메인 및 작업 그룹 설정의 '설정 변경' > 변경 > 영어 이름 변경

 

 

 

 


도움이 되셨다면, 좋아요 / 구독 버튼 눌러주세요~

 

저작물의 저작권은 작성자에게 있습니다.
공유는 자유롭게 하시되 댓글 남겨주세요~
상업적 용도로는 무단 사용을 금지합니다.
끝까지 읽어주셔서 감사합니다^^

반응형
Comments