mirror of
https://github.com/python/cpython.git
synced 2024-11-24 02:15:30 +08:00
SF patch #461413 (Gerhard Häring): Add STARTTLS feature to smtplib
This patch adds the features from RFC 2487 (Secure SMTP over TLS) to the smtplib module: - A starttls() function - Wrapper classes that simulate enough of sockets and files for smtplib, but really wrap a SSLObject - reset the list of known SMTP extensions at each call of ehlo(). This should have been the case anyway.
This commit is contained in:
parent
5f5512d246
commit
f7fcf5eea6
@ -178,6 +178,14 @@ or may raise the following exceptions:
|
||||
\end{description}
|
||||
\end{methoddesc}
|
||||
|
||||
\begin{methoddesc}{starttls}{\optional{keyfile, certfile}}
|
||||
Put the SMTP connection in TLS (Transport Layer Security) mode. All SMTP
|
||||
commands that follow will be encrypted. You should then call ehlo() again.
|
||||
|
||||
If \var{keyfile} and \var{certfile} are provided, these are passed to the
|
||||
socket module's ssl function.
|
||||
\end{methoddesc}
|
||||
|
||||
\begin{methoddesc}{sendmail}{from_addr, to_addrs, msg\optional{,
|
||||
mail_options, rcpt_options}}
|
||||
Send mail. The required arguments are an \rfc{822} from-address
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
'''SMTP/ESMTP client class.
|
||||
|
||||
This should follow RFC 821 (SMTP), RFC 1869 (ESMTP) and RFC 2554 (SMTP
|
||||
Authentication).
|
||||
This should follow RFC 821 (SMTP), RFC 1869 (ESMTP), RFC 2554 (SMTP
|
||||
Authentication) and RFC 2487 (Secure SMTP over TLS).
|
||||
|
||||
Notes:
|
||||
|
||||
@ -124,6 +124,41 @@ class SMTPAuthenticationError(SMTPResponseException):
|
||||
combination provided.
|
||||
"""
|
||||
|
||||
class SSLFakeSocket:
|
||||
"""A fake socket object that really wraps a SSLObject.
|
||||
|
||||
It only supports what is needed in smtplib.
|
||||
"""
|
||||
def __init__(self, realsock, sslobj):
|
||||
self.realsock = realsock
|
||||
self.sslobj = sslobj
|
||||
|
||||
def send(self, str):
|
||||
self.sslobj.write(str)
|
||||
return len(str)
|
||||
|
||||
def close(self):
|
||||
self.realsock.close()
|
||||
|
||||
class SSLFakeFile:
|
||||
"""A fake file like object that really wraps a SSLObject.
|
||||
|
||||
It only supports what is needed in smtplib.
|
||||
"""
|
||||
def __init__( self, sslobj):
|
||||
self.sslobj = sslobj
|
||||
|
||||
def readline(self):
|
||||
str = ""
|
||||
chr = None
|
||||
while chr != "\n":
|
||||
chr = self.sslobj.read(1)
|
||||
str += chr
|
||||
return str
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
def quoteaddr(addr):
|
||||
"""Quote a subset of the email addresses defined by RFC 821.
|
||||
|
||||
@ -333,6 +368,7 @@ class SMTP:
|
||||
Hostname to send for this command defaults to the FQDN of the local
|
||||
host.
|
||||
"""
|
||||
self.esmtp_features = {}
|
||||
if name:
|
||||
self.putcmd("ehlo", name)
|
||||
else:
|
||||
@ -506,6 +542,22 @@ class SMTP:
|
||||
raise SMTPAuthenticationError(code, resp)
|
||||
return (code, resp)
|
||||
|
||||
def starttls(self, keyfile = None, certfile = None):
|
||||
"""Puts the connection to the SMTP server into TLS mode.
|
||||
|
||||
If the server supports TLS, this will encrypt the rest of the SMTP
|
||||
session. If you provide the keyfile and certfile parameters,
|
||||
the identity of the SMTP server and client can be checked. This,
|
||||
however, depends on whether the socket module really checks the
|
||||
certificates.
|
||||
"""
|
||||
(resp, reply) = self.docmd("STARTTLS")
|
||||
if resp == 220:
|
||||
sslobj = socket.ssl(self.sock, keyfile, certfile)
|
||||
self.sock = SSLFakeSocket(self.sock, sslobj)
|
||||
self.file = SSLFakeFile(sslobj)
|
||||
return (resp, reply)
|
||||
|
||||
def sendmail(self, from_addr, to_addrs, msg, mail_options=[],
|
||||
rcpt_options=[]):
|
||||
"""This command performs an entire mail transaction.
|
||||
|
Loading…
Reference in New Issue
Block a user