2013년 4월 12일 금요일

[python] SMTP email 전송 예제

python 공식 홈페이지에는 상당히 흥미로운 예제들이 많이 있다.

이것저것 구경하던 중에 smtplib 모듈을 활용해 이메일을 보내는 예제들이 몇개 있어

코드를 분석해 보고자 한다.

1. 간단한 이메일 전송

# 이메일을 보내기 위한 smtplib 모듈을 import 한다
import smtplib

# 이메일을 보내기 위한 email 모듈을 import 한다
# MIME (Multipurpose Internet Mail Extensions) 는 전자우편을 위한 인터넷 표준이라고 한다.
from email.mime.text import MIMEText

# 텍스트 문서로 구성되어 있는 파일을 읽는다.
# 여기서는 텍스트 파일이 ASCII  문자로만 구성되어 있다고 가정한다.
fp = open(textfile, 'rb')

# utf-8로 인코딩 된 파일을 읽고자 하는 경우
# import codecs
# fp = codecs.open(textfile, 'rb', 'utf-8')
# 로 읽어들이면 될 듯 하다.

# 읽어들인 파일의 텍스트를 MIME 형식으로 바꾼다.
msg = MIMEText(fp.read())
fp.close()

# me == 보내는 사람의 이메일 주소
# you == 받는 사람의 이메일 주소
msg['Subject'] = 'The contents of %s' % textfile # 이메일 제목
msg['From'] = me
msg['To'] = you

# 로컬 SMTP 서버를 사용해서 메세지를 보낸다.
# 이 예제에서는 Header 는 추가하지 않는다.
s = smtplib.SMTP('localhost')
s.sendmail(me, [you], msg.as_string())
s.quit()

# 로컬 SMTP 서버가 없을 경우 계정이 있는 다른 서버를 사용하면 된다.
s = smtplib.SMTP_SSL('smtp.gmail.com',465)
s.login("아이디", "비밀번호")
s.sendmail(me, you, msg.as_string())
s.quit()

2. 디렉토리에 존재하는 이미지 파일을 이메일에 첨부하는 방법
# 이메일을 보내기 위한 smtplib 모듈을 import 한다
import smtplib

# 이메일에 이미지를 첨부하기 위한 모듈들을 import 한다
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart

COMMASPACE = ', '

# 이메일 메세지 컨테이너를 만든다
msg = MIMEMultipart()
msg['Subject'] = 'Our family reunion'

# me == 보내는 사람의 주소
# family = 받는 사람들의 모든 주소
msg['From'] = me
msg['To'] = COMMASPACE.join(family) # join 함수로 받는 사람들의 주소를 합친다
msg.preamble = 'Our family reunion'

# 전송하고자 하는 이미지 파일들이 모두 PNG 파일이라고 가정하자
for file in pngfiles:
    # 바이너리 모드로 전송할 파일들을 연다.
    # MIMEImage 클래스가 자동으로 이미지의 타입을 알아낼 것이다.
    fp = open(file, 'rb')
    img = MIMEImage(fp.read())
    fp.close()
    msg.attach(img)

# 로컬 서버를 통해 메일을 보낸다.
s = smtplib.SMTP('localhost')
s.sendmail(me, family, msg.as_string())
s.quit()

# 로컬 SMTP 서버가 없을 경우 계정이 있는 다른 서버를 사용하면 된다.
s = smtplib.SMTP_SSL('smtp.gmail.com',465)
s.login("아이디", "비밀번호")
s.sendmail(me, you, msg.as_string())
s.quit()

3. 디렉토리내의 모든 파일들을 이메일로 전송하는 방법
#!/usr/bin/env python

import os
import sys
import smtplib
# 파일 확장자를 통해서 MIME 형식을 guessing 하기 위해 mimetypes 모듈을 임포트 한다.
import mimetypes

from optparse import OptionParser

from email import encoders
from email.message import Message
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

COMMASPACE = ', '

def main():
    parser = OptionParser(usage="""\
디렉토리 내의 파일들을 MIME 메세지로 전송함.

Usage: %prog [options]

-o 옵션을 주지 않는다면, 로컬 SMTP 서버를 통해 메일을 전송한다.
이 경우, 로컬 머신에서는 SMTP 서버를 꼭 사용해야 한다.
""")
    parser.add_option('-d', '--directory',
                      type='string', action='store',
                      help="""전송할 파일들이 있는 디렉토리 지정.
                      서브 디렉토리의 파일은 전송되지 않음.""")
    parser.add_option('-o', '--output',
                      type='string', action='store', metavar='FILE',
                      help="""압축될 파일들을 메일로 전송하지 않고 파일로 저장함""")
    parser.add_option('-s', '--sender',
                      type='string', action='store', metavar='SENDER',
                      help='보내는 사람의 메일 주소 (필요)')
    parser.add_option('-r', '--recipient',
                      type='string', action='append', metavar='RECIPIENT',
                      default=[], dest='recipients',
                      help='받는 사람의 메일 주소 (하나 이상 필요)')

    opts, args = parser.parse_args()

    # argument 가 설정되어 있지 않다면 help 메세지를 print 하고 종료
    if not opts.sender or not opts.recipients:
        parser.print_help()
        sys.exit(1)

    # argument 를 바탕으로 디렉토리 설정
    directory = opts.directory
    if not directory:
        directory = '.'

    # MIMEMultipart 클래스를 생성
    outer = MIMEMultipart()
    outer['Subject'] = '%s 디렉토리의 파일' % os.path.abspath(directory)
    outer['To'] = COMMASPACE.join(opts.recipients)
    outer['From'] = opts.sender
    outer.preamble = 'You will not see this in a MIME-aware mail reader.\n'

    # 디렉토리에 존재하는 파일 이름의 리스트에서 for
    for filename in os.listdir(directory):
        path = os.path.join(directory, filename) # 디렉토리와 파일 이름을 합치고, path 에 저장
        if not os.path.isfile(path):
            continue

        # 파일의 확장자를 바탕으로 파일 내용을 guess 한다.
        # 인코딩은 무시되지만, gzip 과 같이 간단한 파일들은 체크해야 한다.
        ctype, encoding = mimetypes.guess_type(path)

        if ctype is None or encoding is not None:
            # 파일 타입을 확인할 수 없거나 인코딩 혹은 압축 되어 있을때는
            # 'octet-stream' 로 정의한다.
            ctype = 'application/octet-stream'

        # ctype 을 '/' 로 나눈다. split 의 두번째 parameter 는 나눌 최대 횟수를 의미한다
        maintype, subtype = ctype.split('/', 1)

        if maintype == 'text': # 텍스트 타입 처리
            fp = open(path)
            msg = MIMEText(fp.read(), _subtype=subtype)
            fp.close()
        elif maintype == 'image': # 이미지 타입 처리
            fp = open(path, 'rb')
            msg = MIMEImage(fp.read(), _subtype=subtype)
            fp.close()
        elif maintype == 'audio': # 오디오 타입 처리
            fp = open(path, 'rb')
            msg = MIMEAudio(fp.read(), _subtype=subtype)
            fp.close()
        else:
            fp = open(path, 'rb')
            msg = MIMEBase(maintype, subtype)
            msg.set_payload(fp.read())
            fp.close()
            # Encode the payload using Base64
            encoders.encode_base64(msg)

        # 파일 이름을 msg 헤더로 추가한다.
        msg.add_header('Content-Disposition', 'attachment', filename=filename)
        outer.attach(msg)

    # 파일로 저장하거나, 메일로 전송한다.
    composed = outer.as_string()
    if opts.output:
        fp = open(opts.output, 'w')
        fp.write(composed)
        fp.close()
    else:
        s = smtplib.SMTP('localhost')
        s.sendmail(opts.sender, opts.recipients, composed)
        s.quit()


if __name__ == '__main__':
    main()
reference : http://docs.python.org/2/library/email-examples.html

댓글 2개:

  1. 학기중에 배운 파이썬으로 간단한 메일 전송 스크립트를 만드는데 아주 큰 도움이 되었습니다 감사합니다

    답글삭제
  2. 감사합니다 덕분에 많은 것을 배우고 갑니다

    답글삭제