smtplib — Клиент протокола SMTP

Источник: Lib/smtplib.py


Модуль smtplib определяет объект клиентской сессии SMTP, который можно использовать для отправки почты на любой интернет-машине с демоном-приемником SMTP или ESMTP. Для получения подробной информации о работе SMTP и ESMTP обратитесь к RFC 821 (Simple Mail Transfer Protocol) и RFC 1869 (SMTP Service Extensions).

Availability: не WASI.

Этот модуль не работает или недоступен на WebAssembly. Дополнительную информацию см. в разделе Платформы WebAssembly.

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

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

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

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

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

Поднимает auditing event smtplib.send с аргументами self, data.

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

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

Added in version 3.5: Теперь поддерживается расширение SMTPUTF8 (RFC 6531).

Изменено в версии 3.9: Если параметр timeout установлен в нулевое значение, он вызовет ошибку 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 равен нулю, используется стандартный порт SMTP-over-SSL (465). Необязательные аргументы local_hostname, timeout и source_address имеют то же значение, что и в классе SMTP. context, также необязательный, может содержать SSLContext и позволяет настраивать различные аспекты безопасного соединения. Пожалуйста, прочитайте Соображения безопасности о лучших практиках.

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

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

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

Изменено в версии 3.9: Если параметр timeout установлен в нулевое значение, то будет поднята ошибка ValueError, чтобы предотвратить создание неблокирующего сокета.

Изменено в версии 3.12: Устаревшие параметры keyfile и certfile были удалены.

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

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

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

Изменено в версии 3.9: Добавлен необязательный параметр timeout.

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

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.SMTPNotSupportedError

Команда или опция не поддерживается сервером.

Added in version 3.5.

exception smtplib.SMTPAuthenticationError

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

См.также

RFC 821 - Простой протокол передачи почты

Определение протокола для SMTP. В этом документе описаны модель, порядок работы и детали протокола SMTP.

RFC 1869 - Расширения службы SMTP

Определение расширений ESMTP для SMTP. Здесь описывается структура для расширения SMTP новыми командами, поддерживается динамическое обнаружение команд, предоставляемых сервером, и определяется несколько дополнительных команд.

Объекты SMTP

У экземпляра SMTP есть следующие методы:

SMTP.set_debuglevel(level)

Установка уровня вывода отладочных сообщений. Значение 1 или True для level приводит к появлению отладочных сообщений для соединения и для всех сообщений, отправленных на сервер и полученных с него. Значение 2 для level приводит к тому, что эти сообщения маркируются по времени.

Изменено в версии 3.5: Добавлен уровень отладки 2.

SMTP.docmd(cmd, args='')

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

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

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

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

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

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

Поднимает auditing event smtplib.connect с аргументами self, host, port.

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, если имя входит в набор расширений служб SMTP, возвращаемых сервером, False в противном случае. Регистр игнорируется.

SMTP.verify(address)

Проверяет валидность адреса на этом сервере с помощью SMTP VRFY. Возвращает кортеж, состоящий из кода 250 и полного адреса RFC 822 (включая имя человека), если адрес пользователя действителен. В противном случае возвращается код SMTP-ошибки 400 или больше и строка ошибки.

Примечание

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

SMTP.login(user, password, *, initial_response_ok=True)

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

SMTPHeloError

Сервер не ответил должным образом на приветствие HELO.

SMTPAuthenticationError

Сервер не принял комбинацию имени пользователя и пароля.

SMTPNotSupportedError

Команда AUTH не поддерживается сервером.

SMTPException

Не найден подходящий метод аутентификации.

Каждый из методов аутентификации, поддерживаемых smtplib, пробуются по очереди, если они объявлены как поддерживаемые сервером. Список поддерживаемых методов аутентификации см. в auth(). initial_response_ok передается в auth().

Необязательный ключевой аргумент initial_response_ok указывает, может ли для методов аутентификации, поддерживающих его, «начальный ответ», как указано в RFC 4954, быть отправлен вместе с командой AUTH, а не требовать вызова/ответа.

Изменено в версии 3.5: SMTPNotSupportedError может быть поднят, и был добавлен параметр initial_response_ok.

SMTP.auth(mechanism, authobject, *, initial_response_ok=True)

Выдать SMTP AUTH команду для указанного механизма аутентификации и обработайте ответ на вызов через автообъект.

mechanism указывает, какой механизм аутентификации будет использоваться в качестве аргумента команды AUTH; допустимыми значениями являются те, которые перечислены в элементе auth в esmtp_features.

authobject должен быть вызываемым объектом, принимающим необязательный единственный аргумент:

data = authobject(challenge=None)

Если необязательный ключевой аргумент initial_response_ok равен true, то authobject() будет вызван первым без аргумента. Он может вернуть RFC 4954 «начальный ответ» в формате ASCII str, который будет закодирован и отправлен с командой AUTH, как показано ниже. Если authobject() не поддерживает начальный ответ (например, потому что требует вызова), то при вызове с помощью challenge=None он должен вернуть None. Если значение initial_response_ok равно false, то authobject() не будет вызываться первым с None.

Если проверка первоначального ответа возвращает None или если initial_response_ok ложно, будет вызван authobject() для обработки ответа вызова сервера; передаваемый ему аргумент challenge будет представлять собой bytes. Он должен вернуть ASCII str данные, которые будут закодированы в base64 и отправлены на сервер.

Класс SMTP предоставляет authobjects для механизмов CRAM-MD5, PLAIN и LOGIN; они называются SMTP.auth_cram_md5, SMTP.auth_plain и SMTP.auth_login соответственно. Все они требуют, чтобы свойства user и password экземпляра SMTP были установлены в соответствующие значения.

Пользовательскому коду обычно не нужно напрямую вызывать auth, вместо этого он может вызвать метод login(), который по очереди опробует каждый из перечисленных механизмов в указанном порядке. Метод auth предназначен для облегчения реализации методов аутентификации, которые не поддерживаются (или еще не поддерживаются) непосредственно методом smtplib.

Added in version 3.5.

SMTP.starttls(*, context=None)

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

Если указаны keyfile и certfile, они используются для создания ssl.SSLContext.

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

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

Изменено в версии 3.12: Устаревшие параметры keyfile и certfile были удалены.

SMTPHeloError

Сервер не ответил должным образом на приветствие HELO.

SMTPNotSupportedError

Сервер не поддерживает расширение STARTTLS.

RuntimeError

Поддержка SSL/TLS недоступна вашему интерпретатору Python.

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

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

Изменено в версии 3.5: Ошибка, возникающая из-за отсутствия поддержки STARTTLS, теперь относится к подклассу SMTPNotSupportedError, а не к базовому SMTPException.

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

Отправить почту. Необходимыми аргументами являются строка RFC 822 с адреса, список строк RFC 822 с адресами (пустая строка будет рассматриваться как список с 1 адресом) и строка сообщения. Вызывающая сторона может передать список опций 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 и сопутствующего сообщения об ошибке, отправленного сервером.

Если SMTPUTF8 включен в mail_options и сервер поддерживает его, from_addr и to_addrs могут содержать символы, отличные от ASCII.

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

SMTPRecipientsRefused

Всем получателям было отказано. Никто не получил письмо. Атрибут recipients объекта исключения представляет собой словарь с информацией об отказавшихся получателях (подобно тому, который возвращается, если хотя бы один получатель был принят).

SMTPHeloError

Сервер не ответил должным образом на приветствие HELO.

SMTPSenderRefused

Сервер не принял from_addr.

SMTPDataError

Сервер ответил с неожиданным кодом ошибки (кроме отказа получателя).

SMTPNotSupportedError

SMTPUTF8 был указан в mail_options, но не поддерживается сервером.

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

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

Изменено в версии 3.5: Добавлена поддержка SMTPUTF8, и SMTPNotSupportedError может быть поднят, если указан SMTPUTF8, но сервер его не поддерживает.

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 5322: from_addr устанавливается в поле Sender, если оно присутствует, а в противном случае - в поле From. to_addrs объединяет значения (если таковые имеются) полей 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. Если любой из адресов в from_addr и to_addrs содержит символы, отличные от ASCII, и сервер не рекламирует поддержку SMTPUTF8, то возникает ошибка SMTPNotSupported. В противном случае Message сериализуется с клоном своего policy с атрибутом utf8, установленным на True, а SMTPUTF8 и BODY=8BITMIME добавляются в mail_options.

Added in version 3.2.

Added in version 3.5: Поддержка интернационализированных адресов (SMTPUTF8).

SMTP.quit()

Прервать сеанс SMTP и закрыть соединение. Верните результат выполнения команды SMTP QUIT.

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

Пример SMTP

В этом примере пользователю предлагается ввести адреса, необходимые для конверта сообщения (адреса «Кому» и «От»), и сообщение, которое нужно доставить. Обратите внимание, что заголовки, которые должны быть включены в сообщение, должны быть включены в сообщение в том виде, в котором они введены; в этом примере не производится никакой обработки заголовков RFC 822. В частности, адреса „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):")

# Add the From: and To: headers at the start!
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: Примеры.