]> granicus.if.org Git - python/commitdiff
Patch #1567274: Support SMTP over TLS.
authorMartin v. Löwis <martin@v.loewis.de>
Fri, 27 Oct 2006 07:13:28 +0000 (07:13 +0000)
committerMartin v. Löwis <martin@v.loewis.de>
Fri, 27 Oct 2006 07:13:28 +0000 (07:13 +0000)
Doc/lib/libsmtplib.tex
Lib/smtplib.py
Misc/ACKS
Misc/NEWS

index 2f87bc483b1a88bc9a1067b9b8d157ed3c71ae91..9943d9f285f9003aba0bf9cbb06b254e03b06fff 100644 (file)
@@ -28,6 +28,18 @@ For normal use, you should only require the initialization/connect,
 included below.
 \end{classdesc}
 
+\begin{classdesc}{SMTP_SSL}{\optional{host\optional{, port\optional{,
+                        local_hostname\optional{,
+                        keyfile\optional{,
+                        certfile}}}}}}
+A \class{SMTP_SSL} instance behaves exactly the same as instance \class{SMTP}.
+\class{SMTP_SSL} should be used for the situations where SSL is required from 
+the beginning of the connection and \method{starttls()} is not appropriate.
+If host is not specified, the local host is used. If port is
+omitted, the standard SMTP-over-SSL port (465) is used. keyfile and certfile
+are also optional - they can contain a PEM formatted private key and
+certificate chain file for the SSL connection.
+\end{classdesc}
 
 A nice selection of exceptions is defined as well:
 
index 9c8c4fa48cbc5a5451d0767fe7127f651f2a4f39..7a677aa79393f40fc351a2132793088189839c0d 100755 (executable)
@@ -52,9 +52,10 @@ from sys import stderr
 __all__ = ["SMTPException","SMTPServerDisconnected","SMTPResponseException",
            "SMTPSenderRefused","SMTPRecipientsRefused","SMTPDataError",
            "SMTPConnectError","SMTPHeloError","SMTPAuthenticationError",
-           "quoteaddr","quotedata","SMTP"]
+           "quoteaddr","quotedata","SMTP","SMTP_SSL"]
 
 SMTP_PORT = 25
+SMTP_SSL_PORT = 465
 CRLF="\r\n"
 
 OLDSTYLE_AUTH = re.compile(r"auth=(.*)", re.I)
@@ -240,6 +241,7 @@ class SMTP:
 
         """
         self.esmtp_features = {}
+        self.default_port = SMTP_PORT
         if host:
             (code, msg) = self.connect(host, port)
             if code != 220:
@@ -271,6 +273,13 @@ class SMTP:
         """
         self.debuglevel = debuglevel
 
+    def _get_socket(self,af, socktype, proto,sa):
+        # This makes it simpler for SMTP_SSL to use the SMTP connect code
+        # and just alter the socket connection bit.
+        self.sock = socket.socket(af, socktype, proto)
+        if self.debuglevel > 0: print>>stderr, 'connect:', (host, port)
+        self.sock.connect(sa)
+
     def connect(self, host='localhost', port = 0):
         """Connect to a host on a given port.
 
@@ -289,16 +298,14 @@ class SMTP:
                 try: port = int(port)
                 except ValueError:
                     raise socket.error, "nonnumeric port"
-        if not port: port = SMTP_PORT
+        if not port: port = self.default_port
         if self.debuglevel > 0: print>>stderr, 'connect:', (host, port)
         msg = "getaddrinfo returns an empty list"
         self.sock = None
         for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
             af, socktype, proto, canonname, sa = res
             try:
-                self.sock = socket.socket(af, socktype, proto)
-                if self.debuglevel > 0: print>>stderr, 'connect:', sa
-                self.sock.connect(sa)
+                self._get_socket(af,socktype,proto,sa)
             except socket.error, msg:
                 if self.debuglevel > 0: print>>stderr, 'connect fail:', msg
                 if self.sock:
@@ -716,6 +723,28 @@ class SMTP:
         self.docmd("quit")
         self.close()
 
+class SMTP_SSL(SMTP):
+    """ This is a subclass derived from SMTP that connects over an SSL encrypted
+    socket (to use this class you need a socket module that was compiled with SSL
+    support). If host is not specified, '' (the local host) is used. If port is
+    omitted, the standard SMTP-over-SSL port (465) is used. keyfile and certfile
+    are also optional - they can contain a PEM formatted private key and
+    certificate chain file for the SSL connection.   
+    """
+    def __init__(self, host = '', port = 0, local_hostname = None,
+                 keyfile = None, certfile = None):
+        self.keyfile = keyfile
+        self.certfile = certfile
+        SMTP.__init__(self,host,port,local_hostname)
+        self.default_port = SMTP_SSL_PORT
+
+    def _get_socket(self,af, socktype, proto,sa):
+        self.sock = socket.socket(af, socktype, proto)
+        if self.debuglevel > 0: print>>stderr, 'connect:', (host, port)
+        self.sock.connect(sa)
+        sslobj = socket.ssl(self.sock, self.keyfile, self.certfile)
+        self.sock = SSLFakeSocket(self.sock, sslobj)
+        self.file = SSLFakeFile(sslobj)
 
 # Test the sendmail method, which tests most of the others.
 # Note: This always sends to localhost.
index 2e507640b88038084ffb6111e588e80532c8be5c..d5d7675bc25d48bf332d6c4693e7ad4a96e917ad 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -613,6 +613,7 @@ William Tanksley
 Christian Tanzer
 Steven Taschuk
 Amy Taylor
+Monty Taylor
 Tobias Thelen
 Robin Thomas
 Eric Tiedemann
index 219bbcf9c661f5b9b638a20e29c1ad5cc4b13570..ab3bf3f8dbcf615de7c6a11cd75c6bf44d28694d 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -84,6 +84,8 @@ Core and builtins
 Library
 -------
 
+- Patch #1567274: Support SMTP over TLS.
+
 - Patch #1560695: Add .note.GNU-stack to ctypes' sysv.S so that
   ctypes isn't considered as requiring executable stacks.