Документация Python неофициальный перевод
Содержание страницы

21.17. smtplib – клиент протокола SMTPsmtplib – SMTP protocol client

Исходный код: Lib/smtplib.py


Модуль smtplib определяет объект сеанса клиента SMTP, который можно использовать для отправки почты на любой компьютер в сети с демоном SMTP или ESMTP. Подробнее о работе SMTP и ESMTP см. в RFC 821 (Протокол простой передачи почты) и RFC 1869 (SMTP Service Extensions).

class smtplib.SMTP(host='', port=0, local_hostname=None, [timeout, ]source_address=None)

Экземпляр SMTP инкапсулирует SMTP-соединение. Он содержит методы, поддерживающие полный набор операций SMTP и ESMTP. Если указаны необязательные параметры host и port, метод connect() вызывается с этими параметрами во время инициализации. Если задан параметр local_hostname, он используется как FQDN локального хоста в команде HELO/EHLO. В противном случае имя локального хоста определяется с помощью socket.getfqdn(). Если вызов connect() возвращает код, отличный от успешного, возбуждается исключение SMTPConnectError. Необязательный параметр timeout задаёт тайм-аут в секундах для блокирующих операций, таких как попытка подключения (если не указан, используется глобальная настройка тайм-аута по умолчанию). Если тайм-аут истекает, возбуждается исключение socket.timeout. Необязательный параметр source_address позволяет привязаться к определённому исходному адресу на машине с несколькими сетевыми интерфейсами и/или к определённому исходному TCP-порту. Он принимает кортеж из двух элементов (host, port), к которому сокет привязывается как к своему исходному адресу перед подключением. Если параметр опущен (или host и port равны '' и/или 0 соответственно), используется поведение ОС по умолчанию.

Для обычного использования достаточно методов инициализации/подключения, sendmail() и quit(). Пример приведён ниже.

Класс SMTP поддерживает оператор with. При таком использовании команда SMTP QUIT отправляется автоматически при выходе из оператора with. Например:

>>> from smtplib import SMTP
>>> with SMTP("domain.org") as smtp:
...     smtp.noop()
...
(250, b'Ok')
>>>

Изменено в версии 3.3: Добавлена поддержка оператора with.

Изменено в версии 3.3: добавлен аргумент source_address.

class smtplib.SMTP_SSL(host='', port=0, local_hostname=None, keyfile=None, certfile=None, [timeout, ]context=None, source_address=None)

Экземпляр SMTP_SSL ведёт себя точно так же, как экземпляры SMTP. SMTP_SSL следует использовать в ситуациях, когда SSL требуется с самого начала соединения и использование starttls() нецелесообразно. Если host не указан, используется локальный хост. Если port равен нулю, используется стандартный порт SMTP-over-SSL (465). Необязательные аргументы local_hostname, timeout и source_address имеют то же значение, что и в классе SMTP. Необязательный параметр context может содержать SSLContext и позволяет настраивать различные аспекты безопасного соединения. Рекомендуется прочитать Рекомендации по безопасности для наилучших практик.

файл ключа и файл сертификата – устаревшая альтернатива контексту, и могут указывать на файл закрытого ключа и цепочки сертификатов в формате PEM для SSL-соединения.

Изменено в версии 3.3: был добавлен параметр context.

Изменено в версии 3.3: добавлен аргумент source_address.

Изменено в версии 3.4: Класс теперь поддерживает проверку имени хоста с помощью ssl.SSLContext.check_hostname и Server Name Indication (см. ssl.HAS_SNI).

class smtplib.LMTP(host='', port=LMTP_PORT, local_hostname=None, source_address=None)

Протокол LMTP, очень похожий на ESMTP, во многом основан на стандартном клиенте SMTP. Для LMTP обычно используются Unix-сокеты, поэтому наш метод connect() должен поддерживать как их, так и обычный сервер host:port. Необязательные аргументы local_hostname и source_address имеют то же значение, что и в классе SMTP. Чтобы указать Unix-сокет, необходимо использовать абсолютный путь для host, начинающийся с '/'.

Поддерживается аутентификация с использованием обычного механизма SMTP. При использовании Unix-сокета LMTP обычно не поддерживает и не требует аутентификации, но возможны исключения.

Также определен неплохой набор исключений:

exception smtplib.SMTPException

Подкласс OSError, являющийся базовым классом исключений для всех остальных исключений, предоставляемых этим модулем.

Изменено в версии 3.4: SMTPException стал подклассом OSError

exception smtplib.SMTPServerDisconnected

Это исключение возбуждается, когда сервер неожиданно разрывает соединение или когда предпринимается попытка использовать экземпляр SMTP до подключения к серверу.

exception smtplib.SMTPResponseException

Базовый класс для всех исключений, включающих код ошибки SMTP. Эти исключения генерируются в некоторых случаях, когда сервер 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.SMTPAuthenticationError

Произошла ошибка аутентификации SMTP. Скорее всего, сервер не принял предоставленную комбинацию имени пользователя и пароля.

См. также

RFC 821 – Простой протокол передачи почты
Определение протокола SMTP. Этот документ описывает модель, порядок работы и детали протокола SMTP.
RFC 1869 – Расширения службы SMTP
Определение расширений ESMTP для SMTP. Описывается инфраструктура для расширения SMTP новыми командами, динамическое обнаружение команд, предоставляемых сервером, и определяются несколько дополнительных команд.

21.17.1. Объекты SMTPSMTP Objects

Экземпляр SMTP имеет следующие методы:

SMTP.set_debuglevel(level)

Устанавливает уровень отладочного вывода. Значение level, равное истине, приводит к выводу отладочных сообщений для соединения и для всех сообщений, отправленных на сервер и полученных от него.

SMTP.docmd(cmd, args='')

Отправляет команду cmd серверу. Необязательный аргумент args просто дописывается к команде через пробел.

Возвращает кортеж из двух элементов: числового кода ответа и собственно строки ответа (многострочные ответы объединяются в одну длинную строку).

При обычной работе нет необходимости явно вызывать этот метод. Он используется для реализации других методов и может быть полезен при тестировании частных расширений.

Если соединение с сервером теряется во время ожидания ответа, будет возбуждено исключение SMTPServerDisconnected.

SMTP.connect(host='localhost', port=0)

Подключается к хосту на указанном порту. По умолчанию подключается к локальному хосту на стандартном порту SMTP (25). Если имя хоста заканчивается на двоеточие (':'), за которым следует число, этот суффикс отбрасывается, а число интерпретируется как номер порта для использования. Этот метод автоматически вызывается конструктором, если хост указан при создании экземпляра. Возвращает кортеж из двух элементов: код ответа и сообщение, отправленное сервером в своём ответе на подключение.

SMTP.helo(name='')

Идентификация на SMTP-сервере выполняется с помощью HELO. Аргумент hostname по умолчанию принимает полностью определённое доменное имя локального хоста. Сообщение, возвращаемое сервером, сохраняется в атрибуте helo_resp объекта.

В обычной работе явно вызывать этот метод не требуется. Он будет вызван неявно методом sendmail() при необходимости.

SMTP.ehlo(name='')

Идентификация на ESMTP-сервере выполняется с помощью EHLO. Аргумент hostname по умолчанию принимает полностью определённое доменное имя локального хоста. Проверить ответ на наличие опций ESMTP и сохранить их для использования методом has_extn(). Также устанавливаются несколько информационных атрибутов: сообщение, возвращаемое сервером, сохраняется в атрибуте ehlo_resp; атрибут does_esmtp устанавливается в true или false в зависимости от того, поддерживает ли сервер ESMTP, а esmtp_features будет словарём, содержащим имена расширений SMTP-сервиса, которые поддерживает этот сервер, и их параметры (если есть).

Если нет необходимости использовать has_extn() перед отправкой почты, вызывать этот метод явно не требуется. Он будет вызван неявно методом sendmail() при необходимости.

SMTP.ehlo_or_helo_if_needed()

Этот метод вызывает ehlo() и/или helo(), если за эту сессию ещё не было предыдущей команды EHLO или HELO. Он сначала пытается использовать ESMTP EHLO.

SMTPHeloError
Сервер не ответил корректно на приветствие HELO.
SMTP.has_extn(name)

Возвращает True, если name присутствует в наборе расширений SMTP-сервиса, возвращённых сервером, иначе False. Регистр не учитывается.

SMTP.verify(address)

Check the validity of an address on this server using SMTP VRFY. Returns a tuple consisting of code 250 and a full RFC 822 address (including human name) if the user address is valid. Otherwise returns an SMTP error code of 400 or greater and an error string.

Примечание

Многие сайты отключают SMTP VRFY, чтобы помешать спамерам.

SMTP.login(user, password)

Выполнить вход на SMTP-сервер, требующий аутентификации. Аргументами являются имя пользователя и пароль для аутентификации. Если за эту сессию ещё не было предыдущей команды EHLO или HELO, этот метод сначала пытается использовать ESMTP EHLO. Этот метод завершится нормально, если аутентификация прошла успешно, или может вызвать следующие исключения:

SMTPHeloError
Сервер не ответил корректно на приветствие HELO.
SMTPAuthenticationError
Сервер не принял комбинацию имя пользователя/пароль.
SMTPException
Не найден подходящий метод аутентификации.
SMTP.starttls(keyfile=None, certfile=None, context=None)

Перевести SMTP-соединение в режим TLS (безопасность транспортного уровня). Все последующие SMTP-команды будут зашифрованы. После этого следует снова вызвать ehlo().

Если указаны keyfile и certfile, они передаются функции ssl() модуля socket.

Необязательный параметр context – это объект ssl.SSLContext; это альтернатива использованию keyfile и certfile, и если он указан, оба keyfile и certfile должны быть None.

Если за эту сессию ещё не было предыдущей команды EHLO или HELO, этот метод сначала пытается использовать ESMTP EHLO.

SMTPHeloError
Сервер не ответил корректно на приветствие HELO.
SMTPException
Сервер не поддерживает расширение STARTTLS.
RuntimeError
Интерпретатор Python не поддерживает SSL/TLS.

Изменено в версии 3.3: был добавлен параметр context.

Изменено в версии 3.4: Теперь метод поддерживает проверку имени хоста с помощью SSLContext.check_hostname и Server Name Indicator (см. HAS_SNI).

SMTP.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[])

Отправка почты. Обязательные аргументы: строка адреса отправителя в формате RFC 822, список строк адресов получателей в формате RFC 822 (отдельная строка будет рассматриваться как список с одним адресом) и строка сообщения. Вызывающий может передать список параметров ESMTP (например, 8bitmime) для использования в командах MAIL FROM как mail_options. Параметры ESMTP (например, команды DSN), которые следует использовать со всеми командами RCPT, можно передать как rcpt_options. (Если нужно использовать разные параметры ESMTP для разных получателей, придётся использовать низкоуровневые методы, такие как mail(), rcpt() и data() для отправки сообщения.)

Примечание

Параметры from_addr и to_addrs используются для построения конверта сообщения, используемого транспортными агентами. sendmail никак не изменяет заголовки сообщения.

msg может быть строкой, содержащей символы в диапазоне ASCII, или байтовой строкой. Строка кодируется в байты с помощью кодека ascii, а отдельные символы \r и \n преобразуются в \r\n. Байтовая строка не изменяется.

Если в этом сеансе ещё не было предыдущей команды EHLO или HELO, этот метод сначала пробует ESMTP EHLO. Если сервер поддерживает ESMTP, ему передаётся размер сообщения и каждый из указанных параметров (если параметр входит в набор возможностей, объявляемых сервером). Если EHLO не удаётся, предпринимается попытка HELO, а параметры ESMTP отбрасываются.

Метод завершается нормально, если почта принята хотя бы одним получателем. В противном случае возбуждается исключение. То есть, если метод не возбуждает исключение, значит, кто-то должен получить ваше письмо. Если метод не возбуждает исключение, он возвращает словарь с одной записью для каждого получателя, которому было отказано. Каждая запись содержит кортеж из кода ошибки SMTP и соответствующего сообщения об ошибке, отправленного сервером.

Этот метод может возбуждать следующие исключения:

SMTPRecipientsRefused
Все получатели были отклонены. Почту не получил никто. Атрибут recipients объекта исключения представляет собой словарь с информацией об отклонённых получателях (аналогичный тому, который возвращается, когда был принят хотя бы один получатель).
SMTPHeloError
Сервер не ответил должным образом на приветствие HELO.
SMTPSenderRefused
Сервер не принял адрес from_addr.
SMTPDataError
Сервер ответил неожиданным кодом ошибки (не связанным с отказом отдельному получателю).

Если не указано иное, соединение остаётся открытым даже после возбуждения исключения.

Изменено в версии 3.2: msg может быть байтовой строкой.

SMTP.send_message(msg, from_addr=None, to_addrs=None, mail_options=[], rcpt_options=[])

Это удобный метод для вызова sendmail() с сообщением, представленным объектом email.message.Message. Аргументы имеют то же значение, что и для sendmail(), за исключением того, что msg является объектом Message.

Если from_addr равно None или to_addrs равно None, send_message заполняет эти аргументы адресами, извлечёнными из заголовков msg в соответствии с RFC 2822: from_addr устанавливается в поле Sender (если оно присутствует), в противном случае – в поле From. to_adresses объединяет значения (если они есть) полей To, Cc и Bcc из msg. Если в сообщении встречается ровно один набор заголовков Resent-*, обычные заголовки игнорируются и используются заголовки Resent-*. Если сообщение содержит более одного набора заголовков Resent-*, возбуждается ValueError, поскольку нет способа однозначно определить самый последний набор заголовков Resent-.

send_message сериализует msg с помощью BytesGenerator с \r\n в качестве linesep и вызывает sendmail() для передачи полученного сообщения. Независимо от значений from_addr и to_addrs, send_message не передаёт никакие заголовки Bcc или Resent-Bcc, которые могут присутствовать в msg.

Новое в версии 3.2.

SMTP.quit()

Завершает сеанс SMTP и закрывает соединение. Возвращает результат команды SMTP QUIT.

Также поддерживаются низкоуровневые методы, соответствующие стандартным командам SMTP/ESMTP: HELP, RSET, NOOP, MAIL, RCPT и DATA. Обычно их не нужно вызывать напрямую, поэтому они здесь не документируются. Подробности см. в коде модуля.

21.17.2. Пример SMTPSMTP Example

Этот пример запрашивает у пользователя адреса, необходимые в конверте сообщения (адреса ‘To’\nи ‘From’), а также само сообщение для отправки. Обратите внимание, что заголовки,\nкоторые должны быть включены в сообщение, должны быть включены в сообщение при вводе; этот\nпример не выполняет никакой обработки заголовков RFC 822. В частности,\nадреса ‘To’ и ‘From’ должны быть явно включены в заголовки сообщения.

import smtplib

def prompt(prompt):
    return input(prompt).strip()

fromaddr = prompt("From: ")
toaddrs  = prompt("To: ").split()
print("Enter message, end with ^D (Unix) or ^Z (Windows):")

# Добавьте заголовки From: и To: в начало!
msg = ("From: %s\r\nTo: %s\r\n\r\n"
       % (fromaddr, ", ".join(toaddrs)))
while True:
    try:
        line = input()
    except EOFError:
        break
    if not line:
        break
    msg = msg + line

print("Message length is", len(msg))

server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()

Примечание

В целом рекомендуется использовать возможности пакета email для создания сообщения электронной почты, которое затем можно отправить с помощью send_message(); см. email: Примеры.