Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

Python으로 이메일에 파일을 첨부해 보내는 방법

텍스트 본문과 파일이 함께 들어 있는 혼합 콘텐츠(mixed content) 이메일을 보내려면 먼저 Content-type 헤더를 multipart/mixed로 설정해야 합니다. 그런 다음 본문 영역과 첨부 파일 영역을 boundary(경계선)로 구분하여 지정합니다.

혼합 콘텐츠 이메일의 기본 구조

경계선(boundary)은 두 개의 하이픈(--) 뒤에 고유한 문자열을 붙여 시작하며, 이 문자열은 이메일 본문 어디에도 등장하지 않아야 합니다. 또한 이메일의 마지막 섹션을 알리는 최종 경계선은 반드시 두 개의 하이픈으로 끝나야 합니다.

첨부 파일은 전송 전에 반드시 base64 방식으로 인코딩해야 합니다. 이진 데이터를 그대로 전송하면 SMTP 전송 중 손상될 수 있기 때문입니다.

전체 예제 코드

다음 예제는 /tmp/test.txt 파일을 첨부 파일로 만들어 직접 전송하는 코드입니다. 원본 예제가 Python 2 문법을 사용하고 있어, 최신 환경에서 바로 실행할 수 있도록 Python 3 문법으로 정리했습니다.

#!/usr/bin/python3
import smtplib
import base64

filename = "/tmp/test.txt"

# 파일을 읽어 base64 형식으로 인코딩
fo = open(filename, "rb")
filecontent = fo.read()
fo.close()
encodedcontent = base64.b64encode(filecontent).decode("utf-8")

sender = 'webmaster@tutorialpoint.com'
receiver = 'amrood.admin@gmail.com'
marker = "AUNIQUEMARKER"

body = """
This is a test email to send an attachment.
"""

# 메인 헤더 정의
part1 = """From: From Person <me@fromdomain.net>
To: To Person <amrood.admin@gmail.com>
Subject: Sending Attachment
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=%s
--%s
""" % (marker, marker)

# 본문 메시지 정의
part2 = """Content-Type: text/plain
Content-Transfer-Encoding: 8bit
%s
--%s
""" % (body, marker)

# 첨부 파일 섹션 정의
part3 = """Content-Type: multipart/mixed; name=\"%s\"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=%s
%s
--%s--
""" % (filename, filename, encodedcontent, marker)

message = part1 + part2 + part3

try:
    smtpObj = smtplib.SMTP('localhost')
    smtpObj.sendmail(sender, receiver, message)
    print("이메일이 성공적으로 전송되었습니다")
except Exception:
    print("오류: 이메일을 보낼 수 없습니다")

코드 단계별 설명

1. 파일 읽기 및 인코딩: 첨부할 파일을 바이너리 모드('rb')로 연 뒤 내용을 읽고, base64.b64encode()를 통해 base64 문자열로 변환합니다.

2. 경계선(marker) 정의: AUNIQUEMARKER라는 고유한 문자열을 경계선으로 사용합니다. 이 값은 실제 서비스에서는 충돌 가능성이 없는 임의의 문자열로 지정하는 것이 좋습니다.

3. 헤더(part1): 발신자·수신자·제목 정보와 함께 Content-Type: multipart/mixed 및 경계선 정보를 선언합니다.

4. 본문(part2): 일반 텍스트(text/plain) 형식의 이메일 본문을 작성한 뒤 경계선으로 구역을 닫습니다.

5. 첨부 파일(part3): Content-Disposition: attachment로 파일임을 명시하고, base64로 인코딩된 파일 내용을 넣습니다. 마지막 경계선은 하이픈 두 개로 종료됩니다.

참고: email 모듈로 더 간단하게 처리하기

위 방식은 MIME 구조를 직접 조립해야 하므로 번거롭고 오류가 발생하기 쉽습니다. Python 3의 표준 라이브러리인 email 모듈을 사용하면 동일한 작업을 훨씬 안전하고 간결하게 처리할 수 있습니다.

from email.message import EmailMessage
import smtplib

msg = EmailMessage()
msg["From"] = "me@fromdomain.net"
msg["To"] = "you@todomain.com"
msg["Subject"] = "첨부 파일 전송 테스트"
msg.set_content("파일과 함께 전달되는 본문입니다.")

with open("/tmp/test.txt", "rb") as f:
    msg.add_attachment(
        f.read(),
        maintype="text",
        subtype="plain",
        filename="test.txt"
    )

with smtplib.SMTP("localhost") as smtp:
    smtp.send_message(msg)

EmailMessage 클래스는 헤더 생성, 경계선 처리, base64 인코딩을 모두 자동으로 수행해 주므로, 실무 프로젝트에서는 이 방식을 사용하는 것을 권장합니다.