#python #email #smtp #python-2.6
#python #Адрес электронной почты #smtp #python-2.6
Вопрос:
Попытка отправить электронное письмо с файлом сертификата с помощью следующего скрипта:
import smtplib
client = smtplib.SMTP(myhost, myport)
client.ehlo()
client.starttls(certfile=mycertfile)
client.ehlo()
client.login(myusername, mypassword)
client.sendmail(sender, receiver, Message)
client.quit()
Я получаю следующую ошибку:
SSLError: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib
Я думаю, что документация (smtplib.html и ssl.html ) скажем, мне нужно предоставить закрытый ключ. У меня есть только файл сертификата (формат base64 PEM). Мой devops говорит, что в этом случае закрытый ключ не требуется, потому что мне не нужно идентифицировать локальную сторону соединения.
Вопрос
Есть ли способ отправить электронное письмо без предоставления закрытого ключа? Если требуется закрытый ключ, зачем?
Комментарии:
1. Ошибка относится к SSLv3 либо потому, что одна из реализаций (клиентская или серверная) понизила рейтинг соединения с TLSv1 до SSLv3, либо потому, что OpenSSL повторно использует коды ошибок для двух реализаций (изменений с SSLv3 на TLSv1 немного). Больше нечего сказать об ошибке, это означает, что ваш файл сертификата не содержит сертификат сервера или цепочку доверия к нему.
Ответ №1:
Существует два способа использования SSL / TLS: аутентификация клиента и «базовый», когда клиент не проходит проверку подлинности. При подключениях с аутентификацией клиента как сервер, так и клиент отправляют сертификат другому. В «basic» это делает только сервер.
Если вы не передаете ни сертификат, ни ключевой файл, smtplib
будет использоваться базовое соединение, в котором клиент аутентифицируется.
Если вы используете сертификат, он будет использоваться для подключения с аутентификацией клиента. В этом случае сервер потребует, чтобы клиент показал, что он владеет сертификатом, подписав сообщение о рукопожатии. Для того, чтобы клиент мог это сделать, ему также необходим закрытый ключ, который может быть либо в файле сертификата, либо в виде отдельного ключевого файла.
Короче говоря, если вы хотите использовать сертификат клиента, вы также должны использовать ключ. Если нет, вы можете просто оставить оба пустыми.
OTOH, может быть, у вас есть файл сертификата сервера или список CA, который вы хотите использовать с подключением?
В этом случае вам нужно передать его ssl.wrap_socket
в ca_certs
параметр. Поскольку вы используете Python 2.6, нет простого способа сделать это с smtplib
помощью (Python 3.3 имеет context
аргумент для starttls).
Как решить эту проблему, зависит от вашего приложения. Например, если вам больше ничего не нужно ssl
, хакерским решением было бы заменить патч ssl.wrap_socket
на тот, который предоставляет ваш ca_cert
(а также cert_reqs=CERT_REQUIRED
, вероятно).
Более полноценным решением было бы расширить smtplib.SMTP
ваш собственный вариант, который позволяет передавать эти параметры.
Ответ №2:
Вот обезьянье исправление, взятое с этой страницы:
class SMTPExt(smtplib.SMTP):
"""
This class extends smtplib.SMTP and overrides the starttls method
allowing extra parameters and forwarding them to ssl.wrap_socket.
"""
def starttls(self, keyfile=None, certfile=None, **kwargs):
self.ehlo_or_helo_if_needed()
if not self.has_extn("starttls"):
raise SMTPException("STARTTLS extension not supported by server.")
(resp, reply) = self.docmd("STARTTLS")
if resp == 220:
self.sock = ssl.wrap_socket(self.sock, keyfile, certfile, **kwargs)
self.file = SSLFakeFile(self.sock)
# RFC 3207:
# The client MUST discard any knowledge obtained from
# the server, such as the list of SMTP service extensions,
# which was not obtained from the TLS negotiation itself.
self.helo_resp = None
self.ehlo_resp = None
self.esmtp_features = {}
self.does_esmtp = 0
return (resp, reply)
Использование корневого сертификата из запросов