`smtplib` — SMTP 프로토콜 클라이언트
smtplib — SMTP 프로토콜 클라이언트
smtplib 모듈은 SMTP 또는 ESMTP 리스너 데몬이 있는 인터넷 머신에 메일을 보내는 데 쓸 수 있는 SMTP 클라이언트 세션 객체를 정의해요. SMTP와 ESMTP 동작의 세부 사항은 RFC 821(Simple Mail Transfer Protocol)과 RFC 1869(SMTP Service Extensions)를 참고하세요.
가용성: WASI 아님. 이 모듈은 WebAssembly에서 동작하지 않거나 사용할 수 없어요.
출처: Python 표준 라이브러리
본문
class smtplib.SMTP(*host=''*, *port=0*, *local_hostname=None*, [*timeout*,] *source_address=None*)
SMTP 인스턴스는 SMTP 연결을 캡슐화해요. SMTP와 ESMTP 연산의 전체 레퍼토리를 지원하는 메서드가 있어요. 선택 host와 port 매개변수가 주어지면 초기화 중에 SMTP connect() 메서드가 그 매개변수로 호출돼요. 지정하면 local_hostname이 HELO/EHLO 명령에서 로컬 호스트의 FQDN으로 쓰여요. 아니면 socket.getfqdn()으로 로컬 호스트 이름을 찾아요. connect() 호출이 성공 코드가 아닌 다른 것을 반환하면 SMTPConnectError가 발생해요. 선택 timeout 매개변수는 연결 시도 같은 블로킹 연산에 대한 초 단위 타임아웃을 지정해요(지정하지 않으면 전역 기본 타임아웃 설정이 사용돼요). 타임아웃이 만료되면 TimeoutError가 발생해요. 선택 source_address 매개변수는 여러 네트워크 인터페이스가 있는 머신에서 특정 소스 주소, 그리고/또는 특정 소스 TCP 포트에 바인딩하게 해줘요. 연결 전에 소켓이 소스 주소로 바인딩할 2-튜플 (host, port)을 받아요. 생략하면 OS 기본 동작이 사용돼요.
보통 사용에서는 초기화/연결, sendmail(), SMTP.quit() 메서드만 필요해요. 아래에 예시가 포함돼 있어요. SMTP 클래스는 with 문을 지원해요. 이렇게 쓰면 with 문이 종료될 때 SMTP QUIT 명령이 자동으로 발행돼요. 예:
>>> from smtplib import SMTP
>>> with SMTP("domain.org") as smtp:
... smtp.noop()
...
(250, b'Ok')
>>>
모든 명령은 인자 self와 data로 감사 이벤트 smtplib.SMTP.send를 발생시켜요. 여기서 data는 원격 호스트로 보내질 바이트예요. 버전 3.3 변경: with 문 지원 추가, source_address 인자 추가. 버전 3.5 추가: SMTPUTF8 확장(RFC 6531) 지원. 버전 3.9 변경: timeout 매개변수가 0으로 설정되면 논블로킹 소켓 생성을 막기 위해 ValueError를 발생시킴.
class smtplib.SMTP_SSL(*host=''*, *port=0*, *local_hostname=None*, *, [*timeout*,] *context=None*, *source_address=None*)
SMTP_SSL 인스턴스는 SMTP 인스턴스와 정확히 똑같이 동작해요. SMTP_SSL은 연결 시작부터 SSL이 필요하고 starttls()를 쓰는 게 적절하지 않은 상황에 써야 해요. host를 지정하지 않으면 로컬 호스트를 사용해요. port가 0이면 표준 SMTP-over-SSL 포트(465)를 사용해요. 선택 local_hostname, timeout, source_address 인자는 SMTP 클래스에서와 같은 의미예요. 선택 사항인 context는 SSLContext를 담을 수 있고 보안 연결의 여러 측면을 설정하게 해줘요. 최선의 방법은 Security considerations를 읽어보세요. 버전 3.12 변경: 폐기된 keyfile과 certfile 매개변수가 제거됨.
class smtplib.LMTP(*host=''*, *port=LMTP_PORT*, *local_hostname=None*, *source_address=None*[, *timeout*])
LMTP 프로토콜은 ESMTP와 매우 비슷하고 표준 SMTP 클라이언트에 크게 기반해요. LMTP에는 Unix 소켓을 쓰는 게 흔해서 connect() 메서드가 일반 host:port 서버와 마찬가지로 그것을 지원해야 해요. 선택 local_hostname과 source_address 인자는 SMTP 클래스에서와 같은 의미예요. Unix 소켓을 지정하려면 host에 '/'로 시작하는 절대 경로를 써야 해요. 인증은 일반 SMTP 메커니즘으로 지원돼요. Unix 소켓을 쓸 때 LMTP는 보통 인증을 지원하거나 요구하지 않지만, 상황에 따라 다를 수 있어요. 버전 3.9 변경: 선택 timeout 매개변수 추가.
예외 (Exceptions)
exception smtplib.SMTPException:OSError의 하위 클래스로, 이 모듈이 제공하는 다른 모든 예외의 기본 예외 클래스예요. 버전 3.4 변경: SMTPException이OSError의 하위 클래스가 됨.exception smtplib.SMTPServerDisconnected: 서버가 예기치 않게 연결을 끊거나, 서버에 연결하기 전에SMTP인스턴스를 사용하려 할 때 발생해요.exception smtplib.SMTPResponseException: SMTP 오류 코드를 포함하는 모든 예외의 기본 클래스예요.smtp_code(오류 코드)와smtp_error(오류 메시지) 속성이 있어요.exception smtplib.SMTPSenderRefused: 발신자 주소가 거부됨. 모든SMTPResponseException예외가 설정하는 속성에 더해 'sender'를 SMTP 서버가 거부한 문자열로 설정해요.exception smtplib.SMTPRecipientsRefused: 모든 수신자 주소가 거부됨.recipients속성은SMTP.sendmail()이 반환하는 것과 정확히 같은 종류의 사전으로 각 수신자의 오류를 담아요.exception smtplib.SMTPDataError: SMTP 서버가 메시지 데이터를 받아들이기를 거부함.exception smtplib.SMTPConnectError: 서버와의 연결 설정 중 오류 발생.exception smtplib.SMTPHeloError: 서버가 우리HELO메시지를 거부함.exception smtplib.SMTPNotSupportedError: 시도한 명령이나 옵션을 서버가 지원하지 않음. 버전 3.5에서 추가.exception smtplib.SMTPAuthenticationError: SMTP 인증이 잘못됨. 대부분 서버가 제공된 사용자 이름/비밀번호 조합을 받아들이지 않았을 거예요.
SMTP 객체 (SMTP Objects)
SMTP 인스턴스에는 다음 메서드가 있어요.
SMTP.set_debuglevel(*level*)
디버그 출력 수준을 설정해요. level이 1이나 True면 연결과 서버에 보내고 받은 모든 메시지에 대한 디버그 메시지가 생성돼요. level이 2면 이 메시지들에 타임스탬프가 붙어요. 버전 3.5 변경: debuglevel 2 추가.
SMTP.docmd(*cmd*, *args=''*)
cmd 명령을 서버에 보내요. 선택 args 인자는 공백으로 구분되어 명령에 이어붙여져요. 숫자 응답 코드와 실제 응답 줄로 구성된 2-튜플을 반환해요(멀티라인 응답은 하나의 긴 줄로 결합됨). 정상 동작에서는 이 메서드를 명시적으로 호출할 필요가 없어요. 응답을 기다리는 동안 서버 연결이 끊어지면 SMTPServerDisconnected가 발생해요.
SMTP.connect(*host='localhost'*, *port=0*)
주어진 포트의 호스트에 연결해요. 기본값은 표준 SMTP 포트(25)의 로컬 호스트에 연결하는 거예요. 호스트 이름이 콜론(':') 뒤에 숫자로 끝나면 그 접미사는 벗겨지고 숫자가 사용할 포트 번호로 해석돼요. 이 메서드는 인스턴스화 중 호스트가 지정되면 생성자가 자동으로 호출해요. 서버가 연결 응답에서 보낸 응답 코드와 메시지의 2-튜플을 반환해요. 감사 이벤트 smtplib.connect를 인자 self, host, port로 발생시켜요.
SMTP.helo(*name=''*)
HELO로 SMTP 서버에 자신을 식별해요. 호스트 이름 인자는 기본적으로 로컬 호스트의 정규화된 도메인 이름이에요. 정상 동작에서는 명시적으로 호출할 필요가 없고, 필요할 때 sendmail()이 암묵적으로 호출해요.
SMTP.ehlo(*name=''*)
EHLO로 ESMTP 서버에 자신을 식별해요. ESMTP 옵션에 대해 응답을 검사하고 has_extn()이 쓰도록 저장해요. 몇 가지 정보 속성도 설정해요: 서버가 반환한 메시지는 ehlo_resp 속성으로, does_esmtp는 서버가 ESMTP를 지원하는지에 따라 True/False로, esmtp_features는 이 서버가 지원하는 SMTP 서비스 확장의 이름과 그 매개변수(있으면)를 담은 사전이 돼요. 메일을 보내기 전에 has_extn()을 쓰려 하지 않는 한 명시적으로 호출할 필요가 없어요.
SMTP.ehlo_or_helo_if_needed()
이 세션에 이전 EHLO나 HELO 명령이 없으면 ehlo() 및/또는 helo()를 호출해요. 먼저 ESMTP EHLO를 시도해요.
SMTP.has_extn(*name*)
name이 서버가 반환한 SMTP 서비스 확장 집합에 있으면 True, 없으면 False를 반환해요. 대소문자는 무시돼요.
SMTP.verify(*address*)
SMTP VRFY로 이 서버에서 주소의 유효성을 확인해요. 사용자 주소가 유효하면 코드 250과 전체 RFC 822 주소(사람 이름 포함)로 구성된 튜플을 반환해요. 아니면 400 이상의 SMTP 오류 코드와 오류 문자열을 반환해요. 많은 사이트가 스패머를 막기 위해 SMTP VRFY를 비활성화해요.
SMTP.login(*user*, *password*, *, *initial_response_ok=True*)
인증이 필요한 SMTP 서버에 로그인해요. 인자는 인증할 사용자 이름과 비밀번호예요. 이 세션에 이전 EHLO나 HELO 명령이 없으면 ESMTP EHLO를 먼저 시도해요. 인증이 성공하면 정상적으로 반환하거나 예외를 발생시킬 수 있어요: SMTPHeloError, SMTPAuthenticationError(사용자 이름/비밀번호 조합을 받아들이지 않음), SMTPNotSupportedError(서버가 AUTH 명령을 지원하지 않음), SMTPException(적합한 인증 방법을 찾지 못함). smtplib이 지원하는 각 인증 방법은 서버가 지원한다고 광고하면 차례로 시도돼요. 지원되는 인증 방법 목록은 auth()를 참고하세요. 선택 키워드 인자 initial_response_ok는 그것을 지원하는 인증 방법에 대해 챌린지/응답을 요구하는 대신 RFC 4954에 지정된 대로 "초기 응답"을 AUTH 명령과 함께 보낼 수 있는지 지정해요. 버전 3.5 변경: SMTPNotSupportedError가 발생할 수 있고 initial_response_ok 매개변수 추가.
SMTP.auth(*mechanism*, *authobject*, *, *initial_response_ok=True*)
지정된 인증 mechanism에 대해 SMTP AUTH 명령을 발행하고, authobject로 챌린지 응답을 처리해요. mechanism은 AUTH 명령의 인자로 쓸 인증 메커니즘을 지정하고, 유효한 값은 esmtp_features의 auth 요소에 나열된 것들이에요. authobject는 선택적 단일 인자를 받는 호출 가능 객체여야 해요: data = authobject(challenge=None). 선택 키워드 인자 initial_response_ok가 참이면 authobject()가 먼저 인자 없이 호출돼요. RFC 4954 "초기 응답" ASCII str을 반환할 수 있고, 그것은 아래처럼 인코딩되어 AUTH 명령과 함께 보내져요. 초기 응답을 지원하지 않으면(예: 챌린지가 필요해서) challenge=None으로 호출될 때 None을 반환해야 해요. 초기 응답 검사가 None을 반환하거나 initial_response_ok가 거짓이면, 서버의 챌린지 응답을 처리하도록 authobject()가 호출되는데, 넘겨지는 challenge 인자는 bytes예요. base64로 인코딩되어 서버로 보내질 ASCII str data를 반환해야 해요. SMTP 클래스는 CRAM-MD5, PLAIN, LOGIN 메커니즘에 대한 authobject를 제공하는데, 각각 SMTP.auth_cram_md5, SMTP.auth_plain, SMTP.auth_login이라고 해요. 사용자 코드는 보통 auth를 직접 호출할 필요가 없고, 위의 각 메커니즘을 나열된 순서대로 차례로 시도하는 login() 메서드를 호출하면 돼요. 버전 3.5에서 추가.
SMTP.starttls(*, *context=None*)
SMTP 연결을 TLS(Transport Layer Security) 모드로 전환해요. 뒤따르는 모든 SMTP 명령은 암호화돼요. 그 다음 ehlo()를 다시 호출해야 해요. 선택 context 매개변수는 ssl.SSLContext 객체예요. 이 세션에 이전 EHLO나 HELO 명령이 없으면 ESMTP EHLO를 먼저 시도해요. 버전 3.12 변경: 폐기된 keyfile과 certfile 매개변수 제거. 예외: SMTPHeloError, SMTPNotSupportedError(서버가 STARTTLS 확장을 지원하지 않음), RuntimeError(Python 인터프리터에 SSL/TLS 지원이 없음).
SMTP.sendmail(*from_addr*, *to_addrs*, *msg*, *mail_options=()*, *rcpt_options=()*)
메일을 보내요. 필수 인자는 RFC 822 from-주소 문자열, RFC 822 to-주소 문자열 목록(홀 문자열은 1개 주소의 목록으로 취급), 메시지 문자열이에요. 호출자는 MAIL FROM 명령에 쓰일 ESMTP 옵션("8bitmime" 같은) 목록을 mail_options로 넘길 수 있어요. 모든 RCPT 명령과 함께 써야 하는 ESMTP 옵션(DSN 명령 같은)은 rcpt_options로 넘길 수 있어요. 각 옵션은 잠재적 키를 포함한 옵션의 전체 텍스트를 담은 문자열로 넘겨야 해요(예: "NOTIFY=SUCCESS,FAILURE"). 서로 다른 수신자에게 서로 다른 ESMTP 옵션을 써야 한다면 mail(), rcpt(), data() 같은 저수준 메서드를 써야 해요.
from_addr과 to_addrs 매개변수는 전송 에이전트가 쓰는 메시지 봉투(envelope)를 만드는 데 사용돼요. sendmail은 메시지 헤더를 어떤 식으로도 수정하지 않아요.
msg는 ASCII 범위의 문자를 담은 문자열 또는 바이트 문자열일 수 있어요. 문자열은 ascii 코덱으로 바이트로 인코딩되고, 홀 \r과 \n 문자는 \r\n 문자로 변환돼요. 바이트 문자열은 수정되지 않아요.
이 세션에 이전 EHLO나 HELO 명령이 없으면 ESMTP EHLO를 먼저 시도해요. 서버가 ESMTP를 하면 메시지 크기와 지정된 각 옵션이 서버에 전달돼요(옵션이 서버가 광고하는 기능 집합에 있으면). EHLO가 실패하면 HELO가 시도되고 ESMTP 옵션은 억제돼요. 메일이 적어도 한 수신자에게 수락되면 이 메서드는 정상적으로 반환해요. 아니면 예외를 발생시켜요. 예외를 발생시키지 않으면, 거부된 각 수신자에 대해 하나의 항목을 가진 사전을 반환해요. 각 항목은 SMTP 오류 코드와 서버가 보낸 오류 메시지의 튜플을 담아요. mail_options에 SMTPUTF8이 포함돼 있고 서버가 지원하면 from_addr과 to_addrs가 비ASCII 문자를 포함할 수 있어요. 예외: SMTPRecipientsRefused(모든 수신자 거부), SMTPHeloError, SMTPSenderRefused(서버가 from_addr을 받아들이지 않음), SMTPDataError, SMTPNotSupportedError(SMTPUTF8이 mail_options에 주어졌지만 서버가 지원하지 않음). 별도 언급이 없으면 예외 발생 후에도 연결은 열려 있어요. 버전 3.2 변경: msg가 바이트 문자열일 수 있음. 버전 3.5 변경: SMTPUTF8 지원 추가.
SMTP.send_message(*msg*, *from_addr=None*, *to_addrs=None*, *mail_options=()*, *rcpt_options=()*)
email.message.Message 객체로 표현된 메시지로 sendmail()을 호출하는 편의 메서드예요. msg가 Message 객체라는 점만 빼면 인자는 sendmail()과 같은 의미예요. from_addr이 None이거나 to_addrs가 None이면 send_message는 RFC 5322에 지정된 대로 msg의 헤더에서 추출한 주소로 그 인자를 채워요: from_addr은 Sender 필드가 있으면 그 값, 아니면 From 필드로 설정돼요. to_addrs는 msg의 To, Cc, Bcc 필드의 값(있으면)을 결합해요. 메시지에 정확히 한 세트의 Resent-* 헤더가 나타나면 일반 헤더는 무시되고 Resent-* 헤더가 대신 쓰여요. 메시지에 둘 이상의 Resent-* 헤더 세트가 있으면 가장 최근 세트를 모호함 없이 감지할 방법이 없어서 ValueError가 발생해요. send_message는 \r\n을 linesep으로 하는 BytesGenerator로 msg를 직렬화하고, 결과 메시지를 전송하기 위해 sendmail()을 호출해요. from_addr과 to_addrs의 값과 무관하게 send_message는 msg에 나타날 수 있는 Bcc나 Resent-Bcc 헤더는 전송하지 않아요. from_addr과 to_addrs의 어떤 주소든 비ASCII 문자를 포함하고 서버가 SMTPUTF8 지원을 광고하지 않으면 SMTPNotSupportedError가 발생해요. 아니면 Message를 utf8 속성이 True로 설정된 policy의 복제본으로 직렬화하고, SMTPUTF8과 BODY=8BITMIME을 mail_options에 추가해요. 버전 3.2에서 추가, 버전 3.5 추가: 국제화 주소(SMTPUTF8) 지원.
SMTP.quit()
SMTP 세션을 종료하고 연결을 닫아요. SMTP QUIT 명령의 결과를 반환해요.
표준 SMTP/ESMTP 명령 HELP, RSET, NOOP, MAIL, RCPT, DATA에 대응하는 저수준 메서드도 지원돼요. 보통 직접 호출할 필요가 없어서 여기서 문서화하지 않아요. 세부 사항은 모듈 코드를 참고하세요.
추가로 SMTP 인스턴스에는 다음 속성이 있어요.
SMTP.helo_resp:HELO명령에 대한 응답.SMTP.ehlo_resp:EHLO명령에 대한 응답.SMTP.does_esmtp: 서버가 ESMTP를 지원하는지 나타내는 불리언.SMTP.esmtp_features: 서버가 지원하는 SMTP 서비스 확장의 이름 사전.
SMTP 예시 (SMTP Example)
이 예시는 메시지 봉투에 필요한 주소('To'와 'From' 주소)와 전송할 메시지를 사용자에게 묻습니다. 메시지에 포함할 헤더는 입력한 메시지에 포함해야 한다는 점을 유의하세요. 이 예시는 RFC 822 헤더를 어떤 처리도 하지 않아요. 특히 'To'와 'From' 주소는 메시지 헤더에 명시적으로 포함해야 해요:
import smtplib
def prompt(title):
return input(title).strip()
from_addr = prompt("From: ")
to_addrs = prompt("To: ").split()
print("Enter message, end with ^D (Unix) or ^Z (Windows):")
# Add the From: and To: headers at the start!
lines = [f"From: {from_addr}", f"To: {', '.join(to_addrs)}", ""]
while True:
try:
line = input()
except EOFError:
break
else:
lines.append(line)
msg = "\r\n".join(lines)
print("Message length is", len(msg))
server = smtplib.SMTP("localhost")
server.set_debuglevel(1)
server.sendmail(from_addr, to_addrs, msg)
server.quit()
참고
일반적으로
send_message()로 보내는 걸 원할 거예요. email: Examples 참고.
더 알아보기
- RFC 821 - Simple Mail Transfer Protocol: SMTP의 프로토콜 정의.
- RFC 1869 - SMTP Service Extensions: SMTP에 대한 ESMTP 확장 정의.