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


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

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. В противном случае имя локального хоста будет найдено с использованием socket.getfqdn(). Если вызов connect() возвращает что-либо, кроме кода успеха, возникает SMTPConnectError. Необязательный параметр timeout указывает тайм-аут в секундах для блокирующих операций, таких как попытка подключения (если не указан, будет использоваться глобальная настройка тайм-аута по умолчанию). По истечении тайм-аута вызывается socket.timeout. Необязательный параметр source_address позволяет выполнить привязку к определенному адресу источника на машине с несколькими сетевыми интерфейсами и/или к определенному TCP- порту источника. Для подключения сокета в качестве адреса источника перед подключением требуется 2-кортеж (хост, порт). Если пропущено (или если у хоста или порта значение '' и/или 0 соответственно), будет использоваться поведение ОС по умолчанию.

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

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

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

Все команды будут вызывать событие аудита smtplib.SMTP.send с аргументами self и data, где data — байты, которые будут отправлены на удаленный хост.

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

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

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

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

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

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

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

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

Не рекомендуется, начиная с версии 3.6: keyfile и certfile устарели в пользу context. Вместо них используйте ssl.SSLContext.load_cert_chain() или позвольте ssl.create_default_context() выбрать за вас доверенные сертификаты CA системы.

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

Запрошенная команда или параметр не поддерживается сервером.

Добавлено в версии 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: Added debuglevel 2.

SMTP.docmd(cmd, args='')

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

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

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

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

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

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

Вызывает событие аудита smtplib.connect с аргументами self, host, port.

SMTP.helo(name='')

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

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

SMTP.ehlo(name='')

Поздороваться с сервером ESMTP, используя EHLO. По умолчанию в качестве аргумента имени хоста используется полное доменное имя локального хоста. Изучите ответ для параметра 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)

Проверить действительность адреса на этом сервере с помощью 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 и обработать ответ на запрос через authobject.

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

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

data = authobject(challenge=None)

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

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

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

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

Добавлено в версии 3.5.

SMTP.starttls(keyfile=None, certfile=None, context=None)

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

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

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

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

Не рекомендуется, начиная с версии 3.6: keyfile и certfile устарели в пользу context. Вместо этого используйте ssl.SSLContext.load_cert_chain() или позвольте ssl.create_default_context() выбрать для вас доверенные сертификаты CA системы.

SMTPHeloError
Сервер не ответил должным образом на приветствие HELO.
SMTPNotSupportedError
Сервер не поддерживает расширение STARTTLS.
RuntimeError
Поддержка SSL/TLS недоступна для вашего интерпретатора Python.

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

Изменено в версии 3.4: Теперь метод поддерживает проверку имени хоста с помощью SSLContext.check_hostname и Индикатор имени сервера (SNI) (см. 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_addrNone или to_addrsNone, 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.

Добавлено в версии 3.2.

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

SMTP.quit()

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

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

Пример SMTP

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

# Добавить заголовки 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: примеры.