blob: a8a7884482cc6340865618770b52cc90cb9a60c7 [file] [log] [blame]
Barry Warsaw4c4bec81998-12-22 03:02:20 +00001#! /usr/bin/env python
2
Barry Warsawa1ae8842000-07-09 21:24:31 +00003'''SMTP/ESMTP client class.
Guido van Rossumbbe323e1998-01-29 17:24:40 +00004
Guido van Rossumf7fcf5e2001-09-14 16:08:44 +00005This should follow RFC 821 (SMTP), RFC 1869 (ESMTP), RFC 2554 (SMTP
6Authentication) and RFC 2487 (Secure SMTP over TLS).
Guido van Rossumbbe323e1998-01-29 17:24:40 +00007
Guido van Rossumfcfb6321998-08-04 15:29:54 +00008Notes:
9
10Please remember, when doing ESMTP, that the names of the SMTP service
Barry Warsaw4c4bec81998-12-22 03:02:20 +000011extensions are NOT the same thing as the option keywords for the RCPT
Guido van Rossumfcfb6321998-08-04 15:29:54 +000012and MAIL commands!
13
Guido van Rossumbbe323e1998-01-29 17:24:40 +000014Example:
15
Barry Warsawa7d9bdf1998-12-22 03:24:27 +000016 >>> import smtplib
17 >>> s=smtplib.SMTP("localhost")
18 >>> print s.help()
19 This is Sendmail version 8.8.4
20 Topics:
21 HELO EHLO MAIL RCPT DATA
22 RSET NOOP QUIT HELP VRFY
23 EXPN VERB ETRN DSN
24 For more info use "HELP <topic>".
25 To report bugs in the implementation send email to
26 sendmail-bugs@sendmail.org.
27 For local information send email to Postmaster at your site.
28 End of HELP info
29 >>> s.putcmd("vrfy","someone@here")
30 >>> s.getreply()
31 (250, "Somebody OverHere <somebody@here.my.org>")
32 >>> s.quit()
Barry Warsawa1ae8842000-07-09 21:24:31 +000033'''
Guido van Rossumbbe323e1998-01-29 17:24:40 +000034
Guido van Rossum98d9fd32000-02-28 15:12:25 +000035# Author: The Dragon De Monsyne <dragondm@integral.org>
36# ESMTP support, test code and doc fixes added by
37# Eric S. Raymond <esr@thyrsus.com>
38# Better RFC 821 compliance (MAIL and RCPT, and CRLF in data)
39# by Carey Evans <c.evans@clear.net.nz>, for picky mail servers.
Guido van Rossumae010462001-09-11 15:57:46 +000040# RFC 2554 (authentication) support by Gerhard Haering <gerhard@bigfoot.de>.
Tim Peters495ad3c2001-01-15 01:36:40 +000041#
Guido van Rossum98d9fd32000-02-28 15:12:25 +000042# This was modified from the Python 1.5 library HTTP lib.
43
Guido van Rossumbbe323e1998-01-29 17:24:40 +000044import socket
Barry Warsaw07201771998-12-22 20:37:36 +000045import re
Georg Brandl5a096e12007-01-22 19:40:21 +000046import email.utils
Guido van Rossumae010462001-09-11 15:57:46 +000047import base64
48import hmac
Georg Brandl5a096e12007-01-22 19:40:21 +000049from email.base64mime import encode as encode_base64
Brett Cannone6f8a892004-07-10 23:14:30 +000050from sys import stderr
Guido van Rossumbbe323e1998-01-29 17:24:40 +000051
Skip Montanaro0de65802001-02-15 22:15:14 +000052__all__ = ["SMTPException","SMTPServerDisconnected","SMTPResponseException",
53 "SMTPSenderRefused","SMTPRecipientsRefused","SMTPDataError",
Guido van Rossumae010462001-09-11 15:57:46 +000054 "SMTPConnectError","SMTPHeloError","SMTPAuthenticationError",
Thomas Woutersa6900e82007-08-30 21:54:39 +000055 "quoteaddr","quotedata","SMTP"]
Skip Montanaro0de65802001-02-15 22:15:14 +000056
Guido van Rossumbbe323e1998-01-29 17:24:40 +000057SMTP_PORT = 25
Martin v. Löwisee82c0e2006-10-27 07:13:28 +000058SMTP_SSL_PORT = 465
Guido van Rossumbbe323e1998-01-29 17:24:40 +000059CRLF="\r\n"
Andrew Kuchling503baf92013-09-15 13:11:47 -040060_MAXLINE = 8192 # more than 8 times larger than RFC 821, 4.5.3
Guido van Rossumbbe323e1998-01-29 17:24:40 +000061
Piers Lauder385a77a2002-07-27 00:38:30 +000062OLDSTYLE_AUTH = re.compile(r"auth=(.*)", re.I)
63
Tim Peters495ad3c2001-01-15 01:36:40 +000064# Exception classes used by this module.
Guido van Rossum296e1431999-04-07 15:03:39 +000065class SMTPException(Exception):
66 """Base class for all exceptions raised by this module."""
67
68class SMTPServerDisconnected(SMTPException):
69 """Not connected to any SMTP server.
70
71 This exception is raised when the server unexpectedly disconnects,
72 or when an attempt is made to use the SMTP instance before
73 connecting it to a server.
74 """
75
76class SMTPResponseException(SMTPException):
77 """Base class for all exceptions that include an SMTP error code.
78
79 These exceptions are generated in some instances when the SMTP
80 server returns an error code. The error code is stored in the
81 `smtp_code' attribute of the error, and the `smtp_error' attribute
82 is set to the error message.
83 """
84
85 def __init__(self, code, msg):
86 self.smtp_code = code
87 self.smtp_error = msg
88 self.args = (code, msg)
89
90class SMTPSenderRefused(SMTPResponseException):
91 """Sender address refused.
Guido van Rossumae010462001-09-11 15:57:46 +000092
Guido van Rossum296e1431999-04-07 15:03:39 +000093 In addition to the attributes set by on all SMTPResponseException
Barry Warsawd25c1b71999-11-28 17:11:06 +000094 exceptions, this sets `sender' to the string that the SMTP refused.
Guido van Rossum296e1431999-04-07 15:03:39 +000095 """
96
97 def __init__(self, code, msg, sender):
98 self.smtp_code = code
99 self.smtp_error = msg
100 self.sender = sender
101 self.args = (code, msg, sender)
102
Guido van Rossum20c92281999-04-21 16:52:20 +0000103class SMTPRecipientsRefused(SMTPException):
Barry Warsawd25c1b71999-11-28 17:11:06 +0000104 """All recipient addresses refused.
Guido van Rossumae010462001-09-11 15:57:46 +0000105
Thomas Wouters7e474022000-07-16 12:04:32 +0000106 The errors for each recipient are accessible through the attribute
Tim Peters495ad3c2001-01-15 01:36:40 +0000107 'recipients', which is a dictionary of exactly the same sort as
108 SMTP.sendmail() returns.
Guido van Rossum296e1431999-04-07 15:03:39 +0000109 """
110
111 def __init__(self, recipients):
112 self.recipients = recipients
113 self.args = ( recipients,)
114
115
Guido van Rossum296e1431999-04-07 15:03:39 +0000116class SMTPDataError(SMTPResponseException):
117 """The SMTP server didn't accept the data."""
118
119class SMTPConnectError(SMTPResponseException):
Barry Warsawd25c1b71999-11-28 17:11:06 +0000120 """Error during connection establishment."""
Guido van Rossum296e1431999-04-07 15:03:39 +0000121
122class SMTPHeloError(SMTPResponseException):
Barry Warsawd25c1b71999-11-28 17:11:06 +0000123 """The server refused our HELO reply."""
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000124
Guido van Rossumae010462001-09-11 15:57:46 +0000125class SMTPAuthenticationError(SMTPResponseException):
126 """Authentication error.
127
128 Most probably the server didn't accept the username/password
129 combination provided.
130 """
Peter Schneider-Kamp7bc82bb2000-08-10 14:02:23 +0000131
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000132def quoteaddr(addr):
133 """Quote a subset of the email addresses defined by RFC 821.
134
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000135 Should be able to handle anything rfc822.parseaddr can handle.
136 """
Raymond Hettinger342456d2002-09-05 01:14:07 +0000137 m = (None, None)
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000138 try:
Georg Brandl5a096e12007-01-22 19:40:21 +0000139 m = email.utils.parseaddr(addr)[1]
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000140 except AttributeError:
141 pass
Raymond Hettinger342456d2002-09-05 01:14:07 +0000142 if m == (None, None): # Indicates parse failure or AttributeError
Georg Brandlbd3bc4d2006-02-17 09:52:53 +0000143 # something weird here.. punt -ddm
Raymond Hettinger342456d2002-09-05 01:14:07 +0000144 return "<%s>" % addr
Georg Brandlbd3bc4d2006-02-17 09:52:53 +0000145 elif m is None:
146 # the sender wants an empty return address
147 return "<>"
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000148 else:
149 return "<%s>" % m
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000150
151def quotedata(data):
152 """Quote data for email.
153
Barry Warsawd25c1b71999-11-28 17:11:06 +0000154 Double leading '.', and change Unix newline '\\n', or Mac '\\r' into
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000155 Internet CRLF end-of-line.
156 """
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000157 return re.sub(r'(?m)^\.', '..',
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000158 re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data))
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000159
Peter Schneider-Kamp7bc82bb2000-08-10 14:02:23 +0000160
Bill Janssen426ea0a2007-08-29 22:35:05 +0000161try:
162 import ssl
163except ImportError:
164 _have_ssl = False
165else:
Bill Janssen426ea0a2007-08-29 22:35:05 +0000166 class SSLFakeFile:
167 """A fake file like object that really wraps a SSLObject.
168
169 It only supports what is needed in smtplib.
170 """
171 def __init__(self, sslobj):
172 self.sslobj = sslobj
173
Andrew Kuchling503baf92013-09-15 13:11:47 -0400174 def readline(self, size=-1):
175 if size < 0:
176 size = None
Bill Janssen426ea0a2007-08-29 22:35:05 +0000177 str = ""
178 chr = None
179 while chr != "\n":
Andrew Kuchling503baf92013-09-15 13:11:47 -0400180 if size is not None and len(str) >= size:
181 break
Bill Janssen426ea0a2007-08-29 22:35:05 +0000182 chr = self.sslobj.read(1)
Sean Reifscheiderac2ed1e2008-03-20 00:46:50 +0000183 if not chr: break
Bill Janssen426ea0a2007-08-29 22:35:05 +0000184 str += chr
185 return str
186
187 def close(self):
188 pass
189
190 _have_ssl = True
191
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000192class SMTP:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000193 """This class manages a connection to an SMTP or ESMTP server.
194 SMTP Objects:
Tim Peters495ad3c2001-01-15 01:36:40 +0000195 SMTP objects have the following attributes:
196 helo_resp
197 This is the message given by the server in response to the
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000198 most recent HELO command.
Tim Peters495ad3c2001-01-15 01:36:40 +0000199
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000200 ehlo_resp
Tim Peters495ad3c2001-01-15 01:36:40 +0000201 This is the message given by the server in response to the
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000202 most recent EHLO command. This is usually multiline.
203
Tim Peters495ad3c2001-01-15 01:36:40 +0000204 does_esmtp
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000205 This is a True value _after you do an EHLO command_, if the
206 server supports ESMTP.
207
Tim Peters495ad3c2001-01-15 01:36:40 +0000208 esmtp_features
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000209 This is a dictionary, which, if the server supports ESMTP,
Barry Warsawd25c1b71999-11-28 17:11:06 +0000210 will _after you do an EHLO command_, contain the names of the
211 SMTP service extensions this server supports, and their
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000212 parameters (if any).
Barry Warsawd25c1b71999-11-28 17:11:06 +0000213
Tim Peters495ad3c2001-01-15 01:36:40 +0000214 Note, all extension names are mapped to lower case in the
215 dictionary.
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000216
Barry Warsawd25c1b71999-11-28 17:11:06 +0000217 See each method's docstrings for details. In general, there is a
218 method of the same name to perform each SMTP command. There is also a
219 method called 'sendmail' that will do an entire mail transaction.
220 """
Guido van Rossum95e6f701998-06-25 02:15:50 +0000221 debuglevel = 0
222 file = None
223 helo_resp = None
Martin v. Löwis1190a382007-03-09 15:35:55 +0000224 ehlo_msg = "ehlo"
Guido van Rossum95e6f701998-06-25 02:15:50 +0000225 ehlo_resp = None
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000226 does_esmtp = 0
Guido van Rossum95e6f701998-06-25 02:15:50 +0000227
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000228 def __init__(self, host='', port=0, local_hostname=None,
229 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000230 """Initialize a new instance.
231
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000232 If specified, `host' is the name of the remote host to which to
233 connect. If specified, `port' specifies the port to which to connect.
Barry Warsawd25c1b71999-11-28 17:11:06 +0000234 By default, smtplib.SMTP_PORT is used. An SMTPConnectError is raised
Neil Schemenauer6730f262002-03-24 15:30:40 +0000235 if the specified `host' doesn't respond correctly. If specified,
Tim Peters863ac442002-04-16 01:38:40 +0000236 `local_hostname` is used as the FQDN of the local host. By default,
237 the local hostname is found using socket.getfqdn().
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000238
239 """
Facundo Batista366d6262007-03-28 18:25:54 +0000240 self.timeout = timeout
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000241 self.esmtp_features = {}
Martin v. Löwisee82c0e2006-10-27 07:13:28 +0000242 self.default_port = SMTP_PORT
Guido van Rossum296e1431999-04-07 15:03:39 +0000243 if host:
244 (code, msg) = self.connect(host, port)
245 if code != 220:
246 raise SMTPConnectError(code, msg)
Raymond Hettingerf13eb552002-06-02 00:40:05 +0000247 if local_hostname is not None:
Barry Warsaw13e34f72002-03-26 20:27:35 +0000248 self.local_hostname = local_hostname
Neil Schemenauer6730f262002-03-24 15:30:40 +0000249 else:
Barry Warsaw13e34f72002-03-26 20:27:35 +0000250 # RFC 2821 says we should use the fqdn in the EHLO/HELO verb, and
251 # if that can't be calculated, that we should use a domain literal
252 # instead (essentially an encoded IP address like [A.B.C.D]).
253 fqdn = socket.getfqdn()
254 if '.' in fqdn:
255 self.local_hostname = fqdn
256 else:
257 # We can't find an fqdn hostname, so use a domain literal
Georg Brandldcdfd222006-03-31 19:34:13 +0000258 addr = '127.0.0.1'
259 try:
260 addr = socket.gethostbyname(socket.gethostname())
261 except socket.gaierror:
262 pass
Barry Warsaw13e34f72002-03-26 20:27:35 +0000263 self.local_hostname = '[%s]' % addr
Tim Peters495ad3c2001-01-15 01:36:40 +0000264
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000265 def set_debuglevel(self, debuglevel):
266 """Set the debug output level.
267
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000268 A non-false value results in debug messages for connection and for all
269 messages sent to and received from the server.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000270
271 """
272 self.debuglevel = debuglevel
273
Facundo Batista366d6262007-03-28 18:25:54 +0000274 def _get_socket(self, port, host, timeout):
Martin v. Löwisee82c0e2006-10-27 07:13:28 +0000275 # This makes it simpler for SMTP_SSL to use the SMTP connect code
276 # and just alter the socket connection bit.
Martin v. Löwisee82c0e2006-10-27 07:13:28 +0000277 if self.debuglevel > 0: print>>stderr, 'connect:', (host, port)
Facundo Batista366d6262007-03-28 18:25:54 +0000278 return socket.create_connection((port, host), timeout)
Martin v. Löwisee82c0e2006-10-27 07:13:28 +0000279
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000280 def connect(self, host='localhost', port = 0):
281 """Connect to a host on a given port.
Guido van Rossum95e6f701998-06-25 02:15:50 +0000282
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000283 If the hostname ends with a colon (`:') followed by a number, and
284 there is no port specified, that suffix will be stripped off and the
285 number interpreted as the port number to use.
Guido van Rossum95e6f701998-06-25 02:15:50 +0000286
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000287 Note: This method is automatically invoked by __init__, if a host is
288 specified during instantiation.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000289
290 """
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000291 if not port and (host.find(':') == host.rfind(':')):
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000292 i = host.rfind(':')
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000293 if i >= 0:
294 host, port = host[:i], host[i+1:]
Eric S. Raymondc013f302001-02-09 05:40:38 +0000295 try: port = int(port)
Eric S. Raymond8d876032001-02-09 10:14:53 +0000296 except ValueError:
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000297 raise socket.error, "nonnumeric port"
Martin v. Löwisee82c0e2006-10-27 07:13:28 +0000298 if not port: port = self.default_port
Brett Cannone6f8a892004-07-10 23:14:30 +0000299 if self.debuglevel > 0: print>>stderr, 'connect:', (host, port)
Facundo Batista366d6262007-03-28 18:25:54 +0000300 self.sock = self._get_socket(host, port, self.timeout)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000301 (code, msg) = self.getreply()
Brett Cannone6f8a892004-07-10 23:14:30 +0000302 if self.debuglevel > 0: print>>stderr, "connect:", msg
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000303 return (code, msg)
Tim Peters495ad3c2001-01-15 01:36:40 +0000304
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000305 def send(self, str):
306 """Send `str' to the server."""
Brett Cannone6f8a892004-07-10 23:14:30 +0000307 if self.debuglevel > 0: print>>stderr, 'send:', repr(str)
Facundo Batista16609332008-02-23 12:27:17 +0000308 if hasattr(self, 'sock') and self.sock:
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000309 try:
Martin v. Löwise12454f2002-02-16 23:06:19 +0000310 self.sock.sendall(str)
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000311 except socket.error:
Barry Warsaw76750972001-12-14 20:34:20 +0000312 self.close()
Guido van Rossum40233ea1999-01-15 03:23:55 +0000313 raise SMTPServerDisconnected('Server not connected')
Guido van Rossumfc40a831998-01-29 17:26:45 +0000314 else:
Guido van Rossum40233ea1999-01-15 03:23:55 +0000315 raise SMTPServerDisconnected('please run connect() first')
Tim Peters495ad3c2001-01-15 01:36:40 +0000316
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000317 def putcmd(self, cmd, args=""):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000318 """Send a command to the server."""
Guido van Rossumdb23d3d1999-06-09 15:13:10 +0000319 if args == "":
320 str = '%s%s' % (cmd, CRLF)
321 else:
322 str = '%s %s%s' % (cmd, args, CRLF)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000323 self.send(str)
Tim Peters495ad3c2001-01-15 01:36:40 +0000324
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000325 def getreply(self):
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000326 """Get a reply from the server.
Tim Peters495ad3c2001-01-15 01:36:40 +0000327
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000328 Returns a tuple consisting of:
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000329
330 - server response code (e.g. '250', or such, if all goes well)
331 Note: returns -1 if it can't read response code.
332
333 - server response string corresponding to response code (multiline
334 responses are converted to a single, multiline string).
Guido van Rossumf123f841999-03-29 20:33:21 +0000335
336 Raises SMTPServerDisconnected if end-of-file is reached.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000337 """
338 resp=[]
Guido van Rossum296e1431999-04-07 15:03:39 +0000339 if self.file is None:
340 self.file = self.sock.makefile('rb')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000341 while 1:
Andrew Kuchling503baf92013-09-15 13:11:47 -0400342 line = self.file.readline(_MAXLINE + 1)
Guido van Rossum296e1431999-04-07 15:03:39 +0000343 if line == '':
344 self.close()
345 raise SMTPServerDisconnected("Connection unexpectedly closed")
Andrew Kuchling503baf92013-09-15 13:11:47 -0400346 if self.debuglevel > 0: print >>stderr, 'reply:', repr(line)
347 if len(line) > _MAXLINE:
348 raise SMTPResponseException(500, "Line too long.")
Eric S. Raymondc013f302001-02-09 05:40:38 +0000349 resp.append(line[4:].strip())
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000350 code=line[:3]
Guido van Rossum296e1431999-04-07 15:03:39 +0000351 # Check that the error code is syntactically correct.
352 # Don't attempt to read a continuation line if it is broken.
353 try:
Eric S. Raymondc013f302001-02-09 05:40:38 +0000354 errcode = int(code)
Guido van Rossum296e1431999-04-07 15:03:39 +0000355 except ValueError:
356 errcode = -1
357 break
Guido van Rossumf123f841999-03-29 20:33:21 +0000358 # Check if multiline response.
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000359 if line[3:4]!="-":
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000360 break
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000361
Eric S. Raymondc013f302001-02-09 05:40:38 +0000362 errmsg = "\n".join(resp)
Tim Peters495ad3c2001-01-15 01:36:40 +0000363 if self.debuglevel > 0:
Brett Cannone6f8a892004-07-10 23:14:30 +0000364 print>>stderr, 'reply: retcode (%s); Msg: %s' % (errcode,errmsg)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000365 return errcode, errmsg
Tim Peters495ad3c2001-01-15 01:36:40 +0000366
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000367 def docmd(self, cmd, args=""):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000368 """Send a command, and return its response code."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000369 self.putcmd(cmd,args)
Guido van Rossum296e1431999-04-07 15:03:39 +0000370 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000371
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000372 # std smtp commands
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000373 def helo(self, name=''):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000374 """SMTP 'helo' command.
375 Hostname to send for this command defaults to the FQDN of the local
376 host.
377 """
Neil Schemenauer6730f262002-03-24 15:30:40 +0000378 self.putcmd("helo", name or self.local_hostname)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000379 (code,msg)=self.getreply()
380 self.helo_resp=msg
Guido van Rossum296e1431999-04-07 15:03:39 +0000381 return (code,msg)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000382
Guido van Rossum95e6f701998-06-25 02:15:50 +0000383 def ehlo(self, name=''):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000384 """ SMTP 'ehlo' command.
385 Hostname to send for this command defaults to the FQDN of the local
386 host.
387 """
Guido van Rossumf7fcf5e2001-09-14 16:08:44 +0000388 self.esmtp_features = {}
Martin v. Löwis1190a382007-03-09 15:35:55 +0000389 self.putcmd(self.ehlo_msg, name or self.local_hostname)
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000390 (code,msg)=self.getreply()
Tim Peters495ad3c2001-01-15 01:36:40 +0000391 # According to RFC1869 some (badly written)
392 # MTA's will disconnect on an ehlo. Toss an exception if
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000393 # that happens -ddm
394 if code == -1 and len(msg) == 0:
Barry Warsaw76750972001-12-14 20:34:20 +0000395 self.close()
Guido van Rossum40233ea1999-01-15 03:23:55 +0000396 raise SMTPServerDisconnected("Server not connected")
Guido van Rossum95e6f701998-06-25 02:15:50 +0000397 self.ehlo_resp=msg
Fred Drake8152d322000-12-12 23:20:45 +0000398 if code != 250:
Guido van Rossum296e1431999-04-07 15:03:39 +0000399 return (code,msg)
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000400 self.does_esmtp=1
Thomas Wouters7e474022000-07-16 12:04:32 +0000401 #parse the ehlo response -ddm
Eric S. Raymondc013f302001-02-09 05:40:38 +0000402 resp=self.ehlo_resp.split('\n')
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000403 del resp[0]
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000404 for each in resp:
Piers Lauder385a77a2002-07-27 00:38:30 +0000405 # To be able to communicate with as many SMTP servers as possible,
406 # we have to take the old-style auth advertisement into account,
407 # because:
408 # 1) Else our SMTP feature parser gets confused.
409 # 2) There are some servers that only advertise the auth methods we
410 # support using the old style.
411 auth_match = OLDSTYLE_AUTH.match(each)
412 if auth_match:
413 # This doesn't remove duplicates, but that's no problem
414 self.esmtp_features["auth"] = self.esmtp_features.get("auth", "") \
415 + " " + auth_match.groups(0)[0]
416 continue
417
Barry Warsawbe22ae62002-04-15 20:03:30 +0000418 # RFC 1869 requires a space between ehlo keyword and parameters.
419 # It's actually stricter, in that only spaces are allowed between
420 # parameters, but were not going to check for that here. Note
421 # that the space isn't present if there are no parameters.
422 m=re.match(r'(?P<feature>[A-Za-z0-9][A-Za-z0-9\-]*) ?',each)
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000423 if m:
Eric S. Raymondc013f302001-02-09 05:40:38 +0000424 feature=m.group("feature").lower()
425 params=m.string[m.end("feature"):].strip()
Piers Lauder385a77a2002-07-27 00:38:30 +0000426 if feature == "auth":
427 self.esmtp_features[feature] = self.esmtp_features.get(feature, "") \
428 + " " + params
429 else:
430 self.esmtp_features[feature]=params
Guido van Rossum296e1431999-04-07 15:03:39 +0000431 return (code,msg)
Guido van Rossum95e6f701998-06-25 02:15:50 +0000432
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000433 def has_extn(self, opt):
434 """Does the server support a given SMTP service extension?"""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000435 return opt.lower() in self.esmtp_features
Guido van Rossum95e6f701998-06-25 02:15:50 +0000436
Guido van Rossum18586f41998-04-03 17:03:13 +0000437 def help(self, args=''):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000438 """SMTP 'help' command.
439 Returns help text from server."""
Guido van Rossum18586f41998-04-03 17:03:13 +0000440 self.putcmd("help", args)
Kurt B. Kaiser58bd1902005-06-26 18:27:36 +0000441 return self.getreply()[1]
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000442
443 def rset(self):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000444 """SMTP 'rset' command -- resets session."""
Guido van Rossum296e1431999-04-07 15:03:39 +0000445 return self.docmd("rset")
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000446
447 def noop(self):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000448 """SMTP 'noop' command -- doesn't do anything :>"""
Guido van Rossum296e1431999-04-07 15:03:39 +0000449 return self.docmd("noop")
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000450
Guido van Rossum95e6f701998-06-25 02:15:50 +0000451 def mail(self,sender,options=[]):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000452 """SMTP 'mail' command -- begins mail xfer session."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000453 optionlist = ''
454 if options and self.does_esmtp:
Eric S. Raymondc013f302001-02-09 05:40:38 +0000455 optionlist = ' ' + ' '.join(options)
Guido van Rossumdb23d3d1999-06-09 15:13:10 +0000456 self.putcmd("mail", "FROM:%s%s" % (quoteaddr(sender) ,optionlist))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000457 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000458
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000459 def rcpt(self,recip,options=[]):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000460 """SMTP 'rcpt' command -- indicates 1 recipient for this mail."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000461 optionlist = ''
462 if options and self.does_esmtp:
Eric S. Raymondc013f302001-02-09 05:40:38 +0000463 optionlist = ' ' + ' '.join(options)
Guido van Rossum348fd061999-01-14 04:18:46 +0000464 self.putcmd("rcpt","TO:%s%s" % (quoteaddr(recip),optionlist))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000465 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000466
467 def data(self,msg):
Tim Peters495ad3c2001-01-15 01:36:40 +0000468 """SMTP 'DATA' command -- sends message data to server.
Guido van Rossum296e1431999-04-07 15:03:39 +0000469
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000470 Automatically quotes lines beginning with a period per rfc821.
Guido van Rossum296e1431999-04-07 15:03:39 +0000471 Raises SMTPDataError if there is an unexpected reply to the
472 DATA command; the return value from this method is the final
473 response code received when the all data is sent.
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000474 """
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000475 self.putcmd("data")
476 (code,repl)=self.getreply()
Brett Cannone6f8a892004-07-10 23:14:30 +0000477 if self.debuglevel >0 : print>>stderr, "data:", (code,repl)
Fred Drake8152d322000-12-12 23:20:45 +0000478 if code != 354:
Guido van Rossum296e1431999-04-07 15:03:39 +0000479 raise SMTPDataError(code,repl)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000480 else:
Guido van Rossum20c92281999-04-21 16:52:20 +0000481 q = quotedata(msg)
482 if q[-2:] != CRLF:
483 q = q + CRLF
484 q = q + "." + CRLF
485 self.send(q)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000486 (code,msg)=self.getreply()
Brett Cannone6f8a892004-07-10 23:14:30 +0000487 if self.debuglevel >0 : print>>stderr, "data:", (code,msg)
Guido van Rossum296e1431999-04-07 15:03:39 +0000488 return (code,msg)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000489
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000490 def verify(self, address):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000491 """SMTP 'verify' command -- checks for address validity."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000492 self.putcmd("vrfy", quoteaddr(address))
493 return self.getreply()
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000494 # a.k.a.
495 vrfy=verify
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000496
497 def expn(self, address):
Facundo Batista16609332008-02-23 12:27:17 +0000498 """SMTP 'expn' command -- expands a mailing list."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000499 self.putcmd("expn", quoteaddr(address))
500 return self.getreply()
501
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000502 # some useful methods
Guido van Rossumae010462001-09-11 15:57:46 +0000503
Gregory P. Smithbde4ae42008-01-17 08:35:49 +0000504 def ehlo_or_helo_if_needed(self):
505 """Call self.ehlo() and/or self.helo() if needed.
506
507 If there has been no previous EHLO or HELO command this session, this
508 method tries ESMTP EHLO first.
509
510 This method may raise the following exceptions:
511
512 SMTPHeloError The server didn't reply properly to
513 the helo greeting.
514 """
515 if self.helo_resp is None and self.ehlo_resp is None:
516 if not (200 <= self.ehlo()[0] <= 299):
517 (code, resp) = self.helo()
518 if not (200 <= code <= 299):
519 raise SMTPHeloError(code, resp)
520
Guido van Rossumae010462001-09-11 15:57:46 +0000521 def login(self, user, password):
522 """Log in on an SMTP server that requires authentication.
523
524 The arguments are:
525 - user: The user name to authenticate with.
526 - password: The password for the authentication.
527
528 If there has been no previous EHLO or HELO command this session, this
529 method tries ESMTP EHLO first.
530
531 This method will return normally if the authentication was successful.
532
533 This method may raise the following exceptions:
534
535 SMTPHeloError The server didn't reply properly to
536 the helo greeting.
537 SMTPAuthenticationError The server didn't accept the username/
538 password combination.
Fred Drake2f8f4d32001-10-13 18:35:32 +0000539 SMTPException No suitable authentication method was
Guido van Rossumae010462001-09-11 15:57:46 +0000540 found.
541 """
542
543 def encode_cram_md5(challenge, user, password):
544 challenge = base64.decodestring(challenge)
545 response = user + " " + hmac.HMAC(password, challenge).hexdigest()
Piers Lauder385a77a2002-07-27 00:38:30 +0000546 return encode_base64(response, eol="")
Guido van Rossumae010462001-09-11 15:57:46 +0000547
548 def encode_plain(user, password):
Johannes Gijsbers25946dd2004-12-06 21:25:26 +0000549 return encode_base64("\0%s\0%s" % (user, password), eol="")
Tim Peters469cdad2002-08-08 20:19:19 +0000550
Guido van Rossumae010462001-09-11 15:57:46 +0000551
552 AUTH_PLAIN = "PLAIN"
553 AUTH_CRAM_MD5 = "CRAM-MD5"
Piers Lauder385a77a2002-07-27 00:38:30 +0000554 AUTH_LOGIN = "LOGIN"
Guido van Rossumae010462001-09-11 15:57:46 +0000555
Gregory P. Smithbde4ae42008-01-17 08:35:49 +0000556 self.ehlo_or_helo_if_needed()
Guido van Rossumae010462001-09-11 15:57:46 +0000557
558 if not self.has_extn("auth"):
559 raise SMTPException("SMTP AUTH extension not supported by server.")
560
561 # Authentication methods the server supports:
562 authlist = self.esmtp_features["auth"].split()
563
564 # List of authentication methods we support: from preferred to
565 # less preferred methods. Except for the purpose of testing the weaker
566 # ones, we prefer stronger methods like CRAM-MD5:
Piers Lauder385a77a2002-07-27 00:38:30 +0000567 preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN]
Guido van Rossumae010462001-09-11 15:57:46 +0000568
569 # Determine the authentication method we'll use
570 authmethod = None
571 for method in preferred_auths:
572 if method in authlist:
573 authmethod = method
574 break
Tim Petersb64bec32001-09-18 02:26:39 +0000575
Guido van Rossumae010462001-09-11 15:57:46 +0000576 if authmethod == AUTH_CRAM_MD5:
577 (code, resp) = self.docmd("AUTH", AUTH_CRAM_MD5)
578 if code == 503:
579 # 503 == 'Error: already authenticated'
580 return (code, resp)
581 (code, resp) = self.docmd(encode_cram_md5(resp, user, password))
582 elif authmethod == AUTH_PLAIN:
Tim Petersb64bec32001-09-18 02:26:39 +0000583 (code, resp) = self.docmd("AUTH",
Guido van Rossumae010462001-09-11 15:57:46 +0000584 AUTH_PLAIN + " " + encode_plain(user, password))
Piers Lauder385a77a2002-07-27 00:38:30 +0000585 elif authmethod == AUTH_LOGIN:
586 (code, resp) = self.docmd("AUTH",
587 "%s %s" % (AUTH_LOGIN, encode_base64(user, eol="")))
588 if code != 334:
589 raise SMTPAuthenticationError(code, resp)
Martin v. Löwis49c05d32002-10-06 17:55:08 +0000590 (code, resp) = self.docmd(encode_base64(password, eol=""))
Raymond Hettinger7fdfc2d2002-05-31 17:49:10 +0000591 elif authmethod is None:
Fred Drake2f8f4d32001-10-13 18:35:32 +0000592 raise SMTPException("No suitable authentication method found.")
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000593 if code not in (235, 503):
Guido van Rossumae010462001-09-11 15:57:46 +0000594 # 235 == 'Authentication successful'
595 # 503 == 'Error: already authenticated'
596 raise SMTPAuthenticationError(code, resp)
597 return (code, resp)
598
Guido van Rossumf7fcf5e2001-09-14 16:08:44 +0000599 def starttls(self, keyfile = None, certfile = None):
600 """Puts the connection to the SMTP server into TLS mode.
Tim Petersb64bec32001-09-18 02:26:39 +0000601
Gregory P. Smithbde4ae42008-01-17 08:35:49 +0000602 If there has been no previous EHLO or HELO command this session, this
603 method tries ESMTP EHLO first.
604
Guido van Rossumf7fcf5e2001-09-14 16:08:44 +0000605 If the server supports TLS, this will encrypt the rest of the SMTP
606 session. If you provide the keyfile and certfile parameters,
607 the identity of the SMTP server and client can be checked. This,
608 however, depends on whether the socket module really checks the
609 certificates.
Gregory P. Smithbde4ae42008-01-17 08:35:49 +0000610
611 This method may raise the following exceptions:
612
613 SMTPHeloError The server didn't reply properly to
614 the helo greeting.
Guido van Rossumf7fcf5e2001-09-14 16:08:44 +0000615 """
Gregory P. Smithbde4ae42008-01-17 08:35:49 +0000616 self.ehlo_or_helo_if_needed()
617 if not self.has_extn("starttls"):
618 raise SMTPException("STARTTLS extension not supported by server.")
Tim Petersb64bec32001-09-18 02:26:39 +0000619 (resp, reply) = self.docmd("STARTTLS")
Guido van Rossumf7fcf5e2001-09-14 16:08:44 +0000620 if resp == 220:
Bill Janssen426ea0a2007-08-29 22:35:05 +0000621 if not _have_ssl:
622 raise RuntimeError("No SSL support included in this Python")
Bill Janssen98d19da2007-09-10 21:51:02 +0000623 self.sock = ssl.wrap_socket(self.sock, keyfile, certfile)
Bill Janssen426ea0a2007-08-29 22:35:05 +0000624 self.file = SSLFakeFile(self.sock)
Gregory P. Smith63bfc1d2008-01-17 07:43:20 +0000625 # RFC 3207:
626 # The client MUST discard any knowledge obtained from
627 # the server, such as the list of SMTP service extensions,
628 # which was not obtained from the TLS negotiation itself.
629 self.helo_resp = None
630 self.ehlo_resp = None
631 self.esmtp_features = {}
632 self.does_esmtp = 0
Guido van Rossumf7fcf5e2001-09-14 16:08:44 +0000633 return (resp, reply)
Tim Petersb64bec32001-09-18 02:26:39 +0000634
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +0000635 def sendmail(self, from_addr, to_addrs, msg, mail_options=[],
Tim Peters495ad3c2001-01-15 01:36:40 +0000636 rcpt_options=[]):
637 """This command performs an entire mail transaction.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000638
Tim Peters495ad3c2001-01-15 01:36:40 +0000639 The arguments are:
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000640 - from_addr : The address sending this mail.
641 - to_addrs : A list of addresses to send this mail to. A bare
642 string will be treated as a list with 1 address.
Tim Peters495ad3c2001-01-15 01:36:40 +0000643 - msg : The message to send.
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000644 - mail_options : List of ESMTP options (such as 8bitmime) for the
645 mail command.
646 - rcpt_options : List of ESMTP options (such as DSN commands) for
647 all the rcpt commands.
648
649 If there has been no previous EHLO or HELO command this session, this
650 method tries ESMTP EHLO first. If the server does ESMTP, message size
651 and each of the specified options will be passed to it. If EHLO
652 fails, HELO will be tried and ESMTP options suppressed.
653
654 This method will return normally if the mail is accepted for at least
Barry Warsawd25c1b71999-11-28 17:11:06 +0000655 one recipient. It returns a dictionary, with one entry for each
656 recipient that was refused. Each entry contains a tuple of the SMTP
657 error code and the accompanying error message sent by the server.
Guido van Rossum296e1431999-04-07 15:03:39 +0000658
659 This method may raise the following exceptions:
660
661 SMTPHeloError The server didn't reply properly to
Tim Peters495ad3c2001-01-15 01:36:40 +0000662 the helo greeting.
Barry Warsawd25c1b71999-11-28 17:11:06 +0000663 SMTPRecipientsRefused The server rejected ALL recipients
Guido van Rossum296e1431999-04-07 15:03:39 +0000664 (no mail was sent).
665 SMTPSenderRefused The server didn't accept the from_addr.
666 SMTPDataError The server replied with an unexpected
667 error code (other than a refusal of
668 a recipient).
669
670 Note: the connection will be open even after an exception is raised.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000671
Guido van Rossum95e6f701998-06-25 02:15:50 +0000672 Example:
Tim Peters495ad3c2001-01-15 01:36:40 +0000673
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000674 >>> import smtplib
675 >>> s=smtplib.SMTP("localhost")
Guido van Rossumfc40a831998-01-29 17:26:45 +0000676 >>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]
Martin v. Löwis301b1cd2002-07-28 16:52:01 +0000677 >>> msg = '''\\
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000678 ... From: Me@my.org
679 ... Subject: testin'...
680 ...
681 ... This is a test '''
682 >>> s.sendmail("me@my.org",tolist,msg)
683 { "three@three.org" : ( 550 ,"User unknown" ) }
684 >>> s.quit()
Tim Peters495ad3c2001-01-15 01:36:40 +0000685
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000686 In the above example, the message was accepted for delivery to three
687 of the four addresses, and one was rejected, with the error code
Barry Warsawd25c1b71999-11-28 17:11:06 +0000688 550. If all addresses are accepted, then the method will return an
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000689 empty dictionary.
690
691 """
Gregory P. Smithbde4ae42008-01-17 08:35:49 +0000692 self.ehlo_or_helo_if_needed()
Guido van Rossum95e6f701998-06-25 02:15:50 +0000693 esmtp_opts = []
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000694 if self.does_esmtp:
695 # Hmmm? what's this? -ddm
696 # self.esmtp_features['7bit']=""
697 if self.has_extn('size'):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000698 esmtp_opts.append("size=%d" % len(msg))
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000699 for option in mail_options:
Guido van Rossum95e6f701998-06-25 02:15:50 +0000700 esmtp_opts.append(option)
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000701
Guido van Rossum95e6f701998-06-25 02:15:50 +0000702 (code,resp) = self.mail(from_addr, esmtp_opts)
Fred Drake8152d322000-12-12 23:20:45 +0000703 if code != 250:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000704 self.rset()
Guido van Rossum296e1431999-04-07 15:03:39 +0000705 raise SMTPSenderRefused(code, resp, from_addr)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000706 senderrs={}
Walter Dörwald65230a22002-06-03 15:58:32 +0000707 if isinstance(to_addrs, basestring):
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +0000708 to_addrs = [to_addrs]
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000709 for each in to_addrs:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000710 (code,resp)=self.rcpt(each, rcpt_options)
Fred Drake8152d322000-12-12 23:20:45 +0000711 if (code != 250) and (code != 251):
Guido van Rossumfc40a831998-01-29 17:26:45 +0000712 senderrs[each]=(code,resp)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000713 if len(senderrs)==len(to_addrs):
Guido van Rossum95e6f701998-06-25 02:15:50 +0000714 # the server refused all our recipients
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000715 self.rset()
Guido van Rossum296e1431999-04-07 15:03:39 +0000716 raise SMTPRecipientsRefused(senderrs)
Fred Drake8152d322000-12-12 23:20:45 +0000717 (code,resp) = self.data(msg)
718 if code != 250:
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000719 self.rset()
Guido van Rossum296e1431999-04-07 15:03:39 +0000720 raise SMTPDataError(code, resp)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000721 #if we got here then somebody got our mail
Tim Peters495ad3c2001-01-15 01:36:40 +0000722 return senderrs
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000723
724
725 def close(self):
726 """Close the connection to the SMTP server."""
727 if self.file:
728 self.file.close()
729 self.file = None
730 if self.sock:
731 self.sock.close()
732 self.sock = None
733
734
735 def quit(self):
Guido van Rossum95e6f701998-06-25 02:15:50 +0000736 """Terminate the SMTP session."""
Georg Brandldeaf2ca2008-03-27 13:27:31 +0000737 res = self.docmd("quit")
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000738 self.close()
Georg Brandldeaf2ca2008-03-27 13:27:31 +0000739 return res
Guido van Rossum95e6f701998-06-25 02:15:50 +0000740
Bill Janssen426ea0a2007-08-29 22:35:05 +0000741if _have_ssl:
Martin v. Löwisee82c0e2006-10-27 07:13:28 +0000742
Bill Janssen426ea0a2007-08-29 22:35:05 +0000743 class SMTP_SSL(SMTP):
744 """ This is a subclass derived from SMTP that connects over an SSL encrypted
745 socket (to use this class you need a socket module that was compiled with SSL
746 support). If host is not specified, '' (the local host) is used. If port is
747 omitted, the standard SMTP-over-SSL port (465) is used. keyfile and certfile
748 are also optional - they can contain a PEM formatted private key and
749 certificate chain file for the SSL connection.
750 """
751 def __init__(self, host='', port=0, local_hostname=None,
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000752 keyfile=None, certfile=None,
753 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Bill Janssen426ea0a2007-08-29 22:35:05 +0000754 self.keyfile = keyfile
755 self.certfile = certfile
756 SMTP.__init__(self, host, port, local_hostname, timeout)
757 self.default_port = SMTP_SSL_PORT
758
759 def _get_socket(self, host, port, timeout):
760 if self.debuglevel > 0: print>>stderr, 'connect:', (host, port)
R. David Murrayeb059b82009-05-23 01:42:42 +0000761 new_socket = socket.create_connection((host, port), timeout)
762 new_socket = ssl.wrap_socket(new_socket, self.keyfile, self.certfile)
763 self.file = SSLFakeFile(new_socket)
764 return new_socket
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000765
Thomas Woutersa6900e82007-08-30 21:54:39 +0000766 __all__.append("SMTP_SSL")
767
Martin v. Löwis1190a382007-03-09 15:35:55 +0000768#
769# LMTP extension
770#
771LMTP_PORT = 2003
772
773class LMTP(SMTP):
774 """LMTP - Local Mail Transfer Protocol
775
776 The LMTP protocol, which is very similar to ESMTP, is heavily based
777 on the standard SMTP client. It's common to use Unix sockets for LMTP,
778 so our connect() method must support that as well as a regular
779 host:port server. To specify a Unix socket, you must use an absolute
780 path as the host, starting with a '/'.
781
782 Authentication is supported, using the regular SMTP mechanism. When
783 using a Unix socket, LMTP generally don't support or require any
784 authentication, but your mileage might vary."""
785
786 ehlo_msg = "lhlo"
Tim Petersea5962f2007-03-12 18:07:52 +0000787
Martin v. Löwis1190a382007-03-09 15:35:55 +0000788 def __init__(self, host = '', port = LMTP_PORT, local_hostname = None):
789 """Initialize a new instance."""
790 SMTP.__init__(self, host, port, local_hostname)
791
Neal Norwitzc8f6c232007-03-10 03:19:18 +0000792 def connect(self, host = 'localhost', port = 0):
Martin v. Löwis1190a382007-03-09 15:35:55 +0000793 """Connect to the LMTP daemon, on either a Unix or a TCP socket."""
Neal Norwitzc8f6c232007-03-10 03:19:18 +0000794 if host[0] != '/':
Martin v. Löwis1190a382007-03-09 15:35:55 +0000795 return SMTP.connect(self, host, port)
796
Neal Norwitzc8f6c232007-03-10 03:19:18 +0000797 # Handle Unix-domain sockets.
798 try:
799 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
800 self.sock.connect(host)
801 except socket.error, msg:
802 if self.debuglevel > 0: print>>stderr, 'connect fail:', host
803 if self.sock:
804 self.sock.close()
805 self.sock = None
806 raise socket.error, msg
807 (code, msg) = self.getreply()
808 if self.debuglevel > 0: print>>stderr, "connect:", msg
809 return (code, msg)
810
Martin v. Löwis1190a382007-03-09 15:35:55 +0000811
Guido van Rossum95e6f701998-06-25 02:15:50 +0000812# Test the sendmail method, which tests most of the others.
813# Note: This always sends to localhost.
814if __name__ == '__main__':
Andrew M. Kuchling6be424f2001-08-13 14:41:39 +0000815 import sys
Guido van Rossum95e6f701998-06-25 02:15:50 +0000816
817 def prompt(prompt):
818 sys.stdout.write(prompt + ": ")
Eric S. Raymondc013f302001-02-09 05:40:38 +0000819 return sys.stdin.readline().strip()
Guido van Rossum95e6f701998-06-25 02:15:50 +0000820
821 fromaddr = prompt("From")
Eric S. Raymond38151ed2001-02-09 07:40:17 +0000822 toaddrs = prompt("To").split(',')
Guido van Rossum95e6f701998-06-25 02:15:50 +0000823 print "Enter message, end with ^D:"
824 msg = ''
825 while 1:
826 line = sys.stdin.readline()
827 if not line:
828 break
829 msg = msg + line
Walter Dörwald70a6b492004-02-12 17:35:32 +0000830 print "Message length is %d" % len(msg)
Guido van Rossum95e6f701998-06-25 02:15:50 +0000831
832 server = SMTP('localhost')
833 server.set_debuglevel(1)
834 server.sendmail(fromaddr, toaddrs, msg)
835 server.quit()