Содержание страницы
21.17. smtplib – клиент протокола SMTP¶smtplib – 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, то при инициализации вызывается метод SMTP connect() с этими параметрами. Если задан local_hostname, он используется как полное доменное имя (FQDN) локального хоста в команде HELO/EHLO. В противном случае локальное имя хоста определяется с помощью socket.getfqdn(). Если вызов connect() возвращает код, отличный от кода успеха, возбуждается исключение SMTPConnectError. Необязательный параметр 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 и source_address имеют тот же смысл, что и в классе SMTP. keyfile и certfile также необязательны и могут содержать файл закрытого ключа в формате PEM и цепочку сертификатов для SSL-соединения. context также необязателен, может содержать SSLContext и является альтернативой keyfile и certfile; если он указан, keyfile и certfile должны быть None. Необязательный параметр timeout задаёт тайм-аут в секундах для блокирующих операций, таких как попытка соединения (если не указан, используется глобальный тайм-аут по умолчанию). Необязательный параметр source_address позволяет привязаться к определённому исходному адресу на машине с несколькими сетевыми интерфейсами и/или к определённому исходному TCP-порту. Он принимает кортеж из двух элементов (host, port), к которому сокет привязывается как к исходному адресу перед соединением. Если параметр опущен (или host или port равны '' и/или 0 соответственно), используется поведение ОС по умолчанию.
Изменено в версии 3.3: был добавлен параметр context.
Изменено в версии 3.3: добавлен аргумент source_address.
- 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¶
Базовый класс исключения для всех остальных исключений, предоставляемых этим модулем.
- 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. Объекты SMTP¶SMTP 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.
- 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. Пример SMTP¶SMTP 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: Примеры.