blob: f9576367f09caca2019134555ee19c3324ce90cf [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
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +000052__all__ = ["SMTPException", "SMTPServerDisconnected", "SMTPResponseException",
53 "SMTPSenderRefused", "SMTPRecipientsRefused", "SMTPDataError",
54 "SMTPConnectError", "SMTPHeloError", "SMTPAuthenticationError",
55 "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
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +000059CRLF = "\r\n"
Guido van Rossumbbe323e1998-01-29 17:24:40 +000060
Piers Lauder385a77a2002-07-27 00:38:30 +000061OLDSTYLE_AUTH = re.compile(r"auth=(.*)", re.I)
62
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +000063
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
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000113 self.args = (recipients,)
Guido van Rossum296e1431999-04-07 15:03:39 +0000114
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
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000132
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000133def quoteaddr(addr):
134 """Quote a subset of the email addresses defined by RFC 821.
135
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000136 Should be able to handle anything rfc822.parseaddr can handle.
137 """
Raymond Hettinger342456d2002-09-05 01:14:07 +0000138 m = (None, None)
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000139 try:
Georg Brandl5a096e12007-01-22 19:40:21 +0000140 m = email.utils.parseaddr(addr)[1]
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000141 except AttributeError:
142 pass
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000143 if m == (None, None): # Indicates parse failure or AttributeError
Georg Brandlbd3bc4d2006-02-17 09:52:53 +0000144 # something weird here.. punt -ddm
Raymond Hettinger342456d2002-09-05 01:14:07 +0000145 return "<%s>" % addr
Georg Brandlbd3bc4d2006-02-17 09:52:53 +0000146 elif m is None:
147 # the sender wants an empty return address
148 return "<>"
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000149 else:
150 return "<%s>" % m
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000151
R David Murray95225952011-07-18 21:34:04 -0400152def _addr_only(addrstring):
153 displayname, addr = email.utils.parseaddr(addrstring)
154 if (displayname, addr) == ('', ''):
155 # parseaddr couldn't parse it, so use it as is.
156 return addrstring
157 return addr
158
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000159def quotedata(data):
160 """Quote data for email.
161
Barry Warsawd25c1b71999-11-28 17:11:06 +0000162 Double leading '.', and change Unix newline '\\n', or Mac '\\r' into
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000163 Internet CRLF end-of-line.
164 """
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000165 return re.sub(r'(?m)^\.', '..',
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000166 re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data))
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000167
Peter Schneider-Kamp7bc82bb2000-08-10 14:02:23 +0000168
Bill Janssen426ea0a2007-08-29 22:35:05 +0000169try:
170 import ssl
171except ImportError:
172 _have_ssl = False
173else:
Bill Janssen426ea0a2007-08-29 22:35:05 +0000174 class SSLFakeFile:
175 """A fake file like object that really wraps a SSLObject.
176
177 It only supports what is needed in smtplib.
178 """
179 def __init__(self, sslobj):
180 self.sslobj = sslobj
181
182 def readline(self):
183 str = ""
184 chr = None
185 while chr != "\n":
186 chr = self.sslobj.read(1)
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000187 if not chr:
188 break
Bill Janssen426ea0a2007-08-29 22:35:05 +0000189 str += chr
190 return str
191
192 def close(self):
193 pass
194
195 _have_ssl = True
196
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000197class SMTP:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000198 """This class manages a connection to an SMTP or ESMTP server.
199 SMTP Objects:
Tim Peters495ad3c2001-01-15 01:36:40 +0000200 SMTP objects have the following attributes:
201 helo_resp
202 This is the message given by the server in response to the
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000203 most recent HELO command.
Tim Peters495ad3c2001-01-15 01:36:40 +0000204
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000205 ehlo_resp
Tim Peters495ad3c2001-01-15 01:36:40 +0000206 This is the message given by the server in response to the
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000207 most recent EHLO command. This is usually multiline.
208
Tim Peters495ad3c2001-01-15 01:36:40 +0000209 does_esmtp
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000210 This is a True value _after you do an EHLO command_, if the
211 server supports ESMTP.
212
Tim Peters495ad3c2001-01-15 01:36:40 +0000213 esmtp_features
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000214 This is a dictionary, which, if the server supports ESMTP,
Barry Warsawd25c1b71999-11-28 17:11:06 +0000215 will _after you do an EHLO command_, contain the names of the
216 SMTP service extensions this server supports, and their
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000217 parameters (if any).
Barry Warsawd25c1b71999-11-28 17:11:06 +0000218
Tim Peters495ad3c2001-01-15 01:36:40 +0000219 Note, all extension names are mapped to lower case in the
220 dictionary.
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000221
Barry Warsawd25c1b71999-11-28 17:11:06 +0000222 See each method's docstrings for details. In general, there is a
223 method of the same name to perform each SMTP command. There is also a
224 method called 'sendmail' that will do an entire mail transaction.
225 """
Guido van Rossum95e6f701998-06-25 02:15:50 +0000226 debuglevel = 0
227 file = None
228 helo_resp = None
Martin v. Löwis1190a382007-03-09 15:35:55 +0000229 ehlo_msg = "ehlo"
Guido van Rossum95e6f701998-06-25 02:15:50 +0000230 ehlo_resp = None
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000231 does_esmtp = 0
Antoine Pitrou21ce8f02011-05-07 19:59:33 +0200232 default_port = SMTP_PORT
Guido van Rossum95e6f701998-06-25 02:15:50 +0000233
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000234 def __init__(self, host='', port=0, local_hostname=None,
235 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000236 """Initialize a new instance.
237
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000238 If specified, `host' is the name of the remote host to which to
239 connect. If specified, `port' specifies the port to which to connect.
Barry Warsawd25c1b71999-11-28 17:11:06 +0000240 By default, smtplib.SMTP_PORT is used. An SMTPConnectError is raised
Neil Schemenauer6730f262002-03-24 15:30:40 +0000241 if the specified `host' doesn't respond correctly. If specified,
Tim Peters863ac442002-04-16 01:38:40 +0000242 `local_hostname` is used as the FQDN of the local host. By default,
243 the local hostname is found using socket.getfqdn().
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000244
245 """
Facundo Batista366d6262007-03-28 18:25:54 +0000246 self.timeout = timeout
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000247 self.esmtp_features = {}
Guido van Rossum296e1431999-04-07 15:03:39 +0000248 if host:
249 (code, msg) = self.connect(host, port)
250 if code != 220:
251 raise SMTPConnectError(code, msg)
Raymond Hettingerf13eb552002-06-02 00:40:05 +0000252 if local_hostname is not None:
Barry Warsaw13e34f72002-03-26 20:27:35 +0000253 self.local_hostname = local_hostname
Neil Schemenauer6730f262002-03-24 15:30:40 +0000254 else:
Barry Warsaw13e34f72002-03-26 20:27:35 +0000255 # RFC 2821 says we should use the fqdn in the EHLO/HELO verb, and
256 # if that can't be calculated, that we should use a domain literal
257 # instead (essentially an encoded IP address like [A.B.C.D]).
258 fqdn = socket.getfqdn()
259 if '.' in fqdn:
260 self.local_hostname = fqdn
261 else:
262 # We can't find an fqdn hostname, so use a domain literal
Georg Brandldcdfd222006-03-31 19:34:13 +0000263 addr = '127.0.0.1'
264 try:
265 addr = socket.gethostbyname(socket.gethostname())
266 except socket.gaierror:
267 pass
Barry Warsaw13e34f72002-03-26 20:27:35 +0000268 self.local_hostname = '[%s]' % addr
Tim Peters495ad3c2001-01-15 01:36:40 +0000269
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000270 def set_debuglevel(self, debuglevel):
271 """Set the debug output level.
272
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000273 A non-false value results in debug messages for connection and for all
274 messages sent to and received from the server.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000275
276 """
277 self.debuglevel = debuglevel
278
Facundo Batista366d6262007-03-28 18:25:54 +0000279 def _get_socket(self, port, host, timeout):
Martin v. Löwisee82c0e2006-10-27 07:13:28 +0000280 # This makes it simpler for SMTP_SSL to use the SMTP connect code
281 # and just alter the socket connection bit.
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000282 if self.debuglevel > 0:
283 print>>stderr, 'connect:', (host, port)
Facundo Batista366d6262007-03-28 18:25:54 +0000284 return socket.create_connection((port, host), timeout)
Martin v. Löwisee82c0e2006-10-27 07:13:28 +0000285
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000286 def connect(self, host='localhost', port=0):
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000287 """Connect to a host on a given port.
Guido van Rossum95e6f701998-06-25 02:15:50 +0000288
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000289 If the hostname ends with a colon (`:') followed by a number, and
290 there is no port specified, that suffix will be stripped off and the
291 number interpreted as the port number to use.
Guido van Rossum95e6f701998-06-25 02:15:50 +0000292
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000293 Note: This method is automatically invoked by __init__, if a host is
294 specified during instantiation.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000295
296 """
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000297 if not port and (host.find(':') == host.rfind(':')):
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000298 i = host.rfind(':')
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000299 if i >= 0:
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000300 host, port = host[:i], host[i + 1:]
301 try:
302 port = int(port)
Eric S. Raymond8d876032001-02-09 10:14:53 +0000303 except ValueError:
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000304 raise socket.error, "nonnumeric port"
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000305 if not port:
306 port = self.default_port
307 if self.debuglevel > 0:
308 print>>stderr, 'connect:', (host, port)
Facundo Batista366d6262007-03-28 18:25:54 +0000309 self.sock = self._get_socket(host, port, self.timeout)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000310 (code, msg) = self.getreply()
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000311 if self.debuglevel > 0:
312 print>>stderr, "connect:", msg
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000313 return (code, msg)
Tim Peters495ad3c2001-01-15 01:36:40 +0000314
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000315 def send(self, str):
316 """Send `str' to the server."""
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000317 if self.debuglevel > 0:
318 print>>stderr, 'send:', repr(str)
Facundo Batista16609332008-02-23 12:27:17 +0000319 if hasattr(self, 'sock') and self.sock:
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000320 try:
Martin v. Löwise12454f2002-02-16 23:06:19 +0000321 self.sock.sendall(str)
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000322 except socket.error:
Barry Warsaw76750972001-12-14 20:34:20 +0000323 self.close()
Guido van Rossum40233ea1999-01-15 03:23:55 +0000324 raise SMTPServerDisconnected('Server not connected')
Guido van Rossumfc40a831998-01-29 17:26:45 +0000325 else:
Guido van Rossum40233ea1999-01-15 03:23:55 +0000326 raise SMTPServerDisconnected('please run connect() first')
Tim Peters495ad3c2001-01-15 01:36:40 +0000327
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000328 def putcmd(self, cmd, args=""):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000329 """Send a command to the server."""
Guido van Rossumdb23d3d1999-06-09 15:13:10 +0000330 if args == "":
331 str = '%s%s' % (cmd, CRLF)
332 else:
333 str = '%s %s%s' % (cmd, args, CRLF)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000334 self.send(str)
Tim Peters495ad3c2001-01-15 01:36:40 +0000335
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000336 def getreply(self):
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000337 """Get a reply from the server.
Tim Peters495ad3c2001-01-15 01:36:40 +0000338
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000339 Returns a tuple consisting of:
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000340
341 - server response code (e.g. '250', or such, if all goes well)
342 Note: returns -1 if it can't read response code.
343
344 - server response string corresponding to response code (multiline
345 responses are converted to a single, multiline string).
Guido van Rossumf123f841999-03-29 20:33:21 +0000346
347 Raises SMTPServerDisconnected if end-of-file is reached.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000348 """
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000349 resp = []
Guido van Rossum296e1431999-04-07 15:03:39 +0000350 if self.file is None:
351 self.file = self.sock.makefile('rb')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000352 while 1:
Kristján Valur Jónsson51a035e2009-01-15 17:20:21 +0000353 try:
354 line = self.file.readline()
355 except socket.error:
356 line = ''
Guido van Rossum296e1431999-04-07 15:03:39 +0000357 if line == '':
358 self.close()
359 raise SMTPServerDisconnected("Connection unexpectedly closed")
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000360 if self.debuglevel > 0:
361 print>>stderr, 'reply:', repr(line)
Eric S. Raymondc013f302001-02-09 05:40:38 +0000362 resp.append(line[4:].strip())
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000363 code = line[:3]
Guido van Rossum296e1431999-04-07 15:03:39 +0000364 # Check that the error code is syntactically correct.
365 # Don't attempt to read a continuation line if it is broken.
366 try:
Eric S. Raymondc013f302001-02-09 05:40:38 +0000367 errcode = int(code)
Guido van Rossum296e1431999-04-07 15:03:39 +0000368 except ValueError:
369 errcode = -1
370 break
Guido van Rossumf123f841999-03-29 20:33:21 +0000371 # Check if multiline response.
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000372 if line[3:4] != "-":
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000373 break
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000374
Eric S. Raymondc013f302001-02-09 05:40:38 +0000375 errmsg = "\n".join(resp)
Tim Peters495ad3c2001-01-15 01:36:40 +0000376 if self.debuglevel > 0:
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000377 print>>stderr, 'reply: retcode (%s); Msg: %s' % (errcode, errmsg)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000378 return errcode, errmsg
Tim Peters495ad3c2001-01-15 01:36:40 +0000379
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000380 def docmd(self, cmd, args=""):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000381 """Send a command, and return its response code."""
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000382 self.putcmd(cmd, args)
Guido van Rossum296e1431999-04-07 15:03:39 +0000383 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000384
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000385 # std smtp commands
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000386 def helo(self, name=''):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000387 """SMTP 'helo' command.
388 Hostname to send for this command defaults to the FQDN of the local
389 host.
390 """
Neil Schemenauer6730f262002-03-24 15:30:40 +0000391 self.putcmd("helo", name or self.local_hostname)
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000392 (code, msg) = self.getreply()
393 self.helo_resp = msg
394 return (code, msg)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000395
Guido van Rossum95e6f701998-06-25 02:15:50 +0000396 def ehlo(self, name=''):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000397 """ SMTP 'ehlo' command.
398 Hostname to send for this command defaults to the FQDN of the local
399 host.
400 """
Guido van Rossumf7fcf5e2001-09-14 16:08:44 +0000401 self.esmtp_features = {}
Martin v. Löwis1190a382007-03-09 15:35:55 +0000402 self.putcmd(self.ehlo_msg, name or self.local_hostname)
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000403 (code, msg) = self.getreply()
Tim Peters495ad3c2001-01-15 01:36:40 +0000404 # According to RFC1869 some (badly written)
405 # MTA's will disconnect on an ehlo. Toss an exception if
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000406 # that happens -ddm
407 if code == -1 and len(msg) == 0:
Barry Warsaw76750972001-12-14 20:34:20 +0000408 self.close()
Guido van Rossum40233ea1999-01-15 03:23:55 +0000409 raise SMTPServerDisconnected("Server not connected")
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000410 self.ehlo_resp = msg
Fred Drake8152d322000-12-12 23:20:45 +0000411 if code != 250:
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000412 return (code, msg)
413 self.does_esmtp = 1
Thomas Wouters7e474022000-07-16 12:04:32 +0000414 #parse the ehlo response -ddm
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000415 resp = self.ehlo_resp.split('\n')
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000416 del resp[0]
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000417 for each in resp:
Piers Lauder385a77a2002-07-27 00:38:30 +0000418 # To be able to communicate with as many SMTP servers as possible,
419 # we have to take the old-style auth advertisement into account,
420 # because:
421 # 1) Else our SMTP feature parser gets confused.
422 # 2) There are some servers that only advertise the auth methods we
423 # support using the old style.
424 auth_match = OLDSTYLE_AUTH.match(each)
425 if auth_match:
426 # This doesn't remove duplicates, but that's no problem
427 self.esmtp_features["auth"] = self.esmtp_features.get("auth", "") \
428 + " " + auth_match.groups(0)[0]
429 continue
430
Barry Warsawbe22ae62002-04-15 20:03:30 +0000431 # RFC 1869 requires a space between ehlo keyword and parameters.
432 # It's actually stricter, in that only spaces are allowed between
433 # parameters, but were not going to check for that here. Note
434 # that the space isn't present if there are no parameters.
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000435 m = re.match(r'(?P<feature>[A-Za-z0-9][A-Za-z0-9\-]*) ?', each)
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000436 if m:
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000437 feature = m.group("feature").lower()
438 params = m.string[m.end("feature"):].strip()
Piers Lauder385a77a2002-07-27 00:38:30 +0000439 if feature == "auth":
440 self.esmtp_features[feature] = self.esmtp_features.get(feature, "") \
441 + " " + params
442 else:
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000443 self.esmtp_features[feature] = params
444 return (code, msg)
Guido van Rossum95e6f701998-06-25 02:15:50 +0000445
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000446 def has_extn(self, opt):
447 """Does the server support a given SMTP service extension?"""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000448 return opt.lower() in self.esmtp_features
Guido van Rossum95e6f701998-06-25 02:15:50 +0000449
Guido van Rossum18586f41998-04-03 17:03:13 +0000450 def help(self, args=''):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000451 """SMTP 'help' command.
452 Returns help text from server."""
Guido van Rossum18586f41998-04-03 17:03:13 +0000453 self.putcmd("help", args)
Kurt B. Kaiser58bd1902005-06-26 18:27:36 +0000454 return self.getreply()[1]
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000455
456 def rset(self):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000457 """SMTP 'rset' command -- resets session."""
Guido van Rossum296e1431999-04-07 15:03:39 +0000458 return self.docmd("rset")
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000459
460 def noop(self):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000461 """SMTP 'noop' command -- doesn't do anything :>"""
Guido van Rossum296e1431999-04-07 15:03:39 +0000462 return self.docmd("noop")
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000463
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000464 def mail(self, sender, options=[]):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000465 """SMTP 'mail' command -- begins mail xfer session."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000466 optionlist = ''
467 if options and self.does_esmtp:
Eric S. Raymondc013f302001-02-09 05:40:38 +0000468 optionlist = ' ' + ' '.join(options)
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000469 self.putcmd("mail", "FROM:%s%s" % (quoteaddr(sender), optionlist))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000470 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000471
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000472 def rcpt(self, recip, options=[]):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000473 """SMTP 'rcpt' command -- indicates 1 recipient for this mail."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000474 optionlist = ''
475 if options and self.does_esmtp:
Eric S. Raymondc013f302001-02-09 05:40:38 +0000476 optionlist = ' ' + ' '.join(options)
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000477 self.putcmd("rcpt", "TO:%s%s" % (quoteaddr(recip), optionlist))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000478 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000479
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000480 def data(self, msg):
Tim Peters495ad3c2001-01-15 01:36:40 +0000481 """SMTP 'DATA' command -- sends message data to server.
Guido van Rossum296e1431999-04-07 15:03:39 +0000482
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000483 Automatically quotes lines beginning with a period per rfc821.
Guido van Rossum296e1431999-04-07 15:03:39 +0000484 Raises SMTPDataError if there is an unexpected reply to the
485 DATA command; the return value from this method is the final
486 response code received when the all data is sent.
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000487 """
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000488 self.putcmd("data")
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000489 (code, repl) = self.getreply()
490 if self.debuglevel > 0:
491 print>>stderr, "data:", (code, repl)
Fred Drake8152d322000-12-12 23:20:45 +0000492 if code != 354:
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000493 raise SMTPDataError(code, repl)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000494 else:
Guido van Rossum20c92281999-04-21 16:52:20 +0000495 q = quotedata(msg)
496 if q[-2:] != CRLF:
497 q = q + CRLF
498 q = q + "." + CRLF
499 self.send(q)
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000500 (code, msg) = self.getreply()
501 if self.debuglevel > 0:
502 print>>stderr, "data:", (code, msg)
503 return (code, msg)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000504
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000505 def verify(self, address):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000506 """SMTP 'verify' command -- checks for address validity."""
R David Murray95225952011-07-18 21:34:04 -0400507 self.putcmd("vrfy", _addr_only(address))
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000508 return self.getreply()
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000509 # a.k.a.
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000510 vrfy = verify
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000511
512 def expn(self, address):
Facundo Batista16609332008-02-23 12:27:17 +0000513 """SMTP 'expn' command -- expands a mailing list."""
R David Murray95225952011-07-18 21:34:04 -0400514 self.putcmd("expn", _addr_only(address))
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000515 return self.getreply()
516
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000517 # some useful methods
Guido van Rossumae010462001-09-11 15:57:46 +0000518
Gregory P. Smithbde4ae42008-01-17 08:35:49 +0000519 def ehlo_or_helo_if_needed(self):
520 """Call self.ehlo() and/or self.helo() if needed.
521
522 If there has been no previous EHLO or HELO command this session, this
523 method tries ESMTP EHLO first.
524
525 This method may raise the following exceptions:
526
527 SMTPHeloError The server didn't reply properly to
528 the helo greeting.
529 """
530 if self.helo_resp is None and self.ehlo_resp is None:
531 if not (200 <= self.ehlo()[0] <= 299):
532 (code, resp) = self.helo()
533 if not (200 <= code <= 299):
534 raise SMTPHeloError(code, resp)
535
Guido van Rossumae010462001-09-11 15:57:46 +0000536 def login(self, user, password):
537 """Log in on an SMTP server that requires authentication.
538
539 The arguments are:
540 - user: The user name to authenticate with.
541 - password: The password for the authentication.
542
543 If there has been no previous EHLO or HELO command this session, this
544 method tries ESMTP EHLO first.
545
546 This method will return normally if the authentication was successful.
547
548 This method may raise the following exceptions:
549
550 SMTPHeloError The server didn't reply properly to
551 the helo greeting.
552 SMTPAuthenticationError The server didn't accept the username/
553 password combination.
Fred Drake2f8f4d32001-10-13 18:35:32 +0000554 SMTPException No suitable authentication method was
Guido van Rossumae010462001-09-11 15:57:46 +0000555 found.
556 """
557
558 def encode_cram_md5(challenge, user, password):
559 challenge = base64.decodestring(challenge)
560 response = user + " " + hmac.HMAC(password, challenge).hexdigest()
Piers Lauder385a77a2002-07-27 00:38:30 +0000561 return encode_base64(response, eol="")
Guido van Rossumae010462001-09-11 15:57:46 +0000562
563 def encode_plain(user, password):
Johannes Gijsbers25946dd2004-12-06 21:25:26 +0000564 return encode_base64("\0%s\0%s" % (user, password), eol="")
Tim Peters469cdad2002-08-08 20:19:19 +0000565
Guido van Rossumae010462001-09-11 15:57:46 +0000566
567 AUTH_PLAIN = "PLAIN"
568 AUTH_CRAM_MD5 = "CRAM-MD5"
Piers Lauder385a77a2002-07-27 00:38:30 +0000569 AUTH_LOGIN = "LOGIN"
Guido van Rossumae010462001-09-11 15:57:46 +0000570
Gregory P. Smithbde4ae42008-01-17 08:35:49 +0000571 self.ehlo_or_helo_if_needed()
Guido van Rossumae010462001-09-11 15:57:46 +0000572
573 if not self.has_extn("auth"):
574 raise SMTPException("SMTP AUTH extension not supported by server.")
575
576 # Authentication methods the server supports:
577 authlist = self.esmtp_features["auth"].split()
578
579 # List of authentication methods we support: from preferred to
580 # less preferred methods. Except for the purpose of testing the weaker
581 # ones, we prefer stronger methods like CRAM-MD5:
Piers Lauder385a77a2002-07-27 00:38:30 +0000582 preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN]
Guido van Rossumae010462001-09-11 15:57:46 +0000583
584 # Determine the authentication method we'll use
585 authmethod = None
586 for method in preferred_auths:
587 if method in authlist:
588 authmethod = method
589 break
Tim Petersb64bec32001-09-18 02:26:39 +0000590
Guido van Rossumae010462001-09-11 15:57:46 +0000591 if authmethod == AUTH_CRAM_MD5:
592 (code, resp) = self.docmd("AUTH", AUTH_CRAM_MD5)
593 if code == 503:
594 # 503 == 'Error: already authenticated'
595 return (code, resp)
596 (code, resp) = self.docmd(encode_cram_md5(resp, user, password))
597 elif authmethod == AUTH_PLAIN:
Tim Petersb64bec32001-09-18 02:26:39 +0000598 (code, resp) = self.docmd("AUTH",
Guido van Rossumae010462001-09-11 15:57:46 +0000599 AUTH_PLAIN + " " + encode_plain(user, password))
Piers Lauder385a77a2002-07-27 00:38:30 +0000600 elif authmethod == AUTH_LOGIN:
601 (code, resp) = self.docmd("AUTH",
602 "%s %s" % (AUTH_LOGIN, encode_base64(user, eol="")))
603 if code != 334:
604 raise SMTPAuthenticationError(code, resp)
Martin v. Löwis49c05d32002-10-06 17:55:08 +0000605 (code, resp) = self.docmd(encode_base64(password, eol=""))
Raymond Hettinger7fdfc2d2002-05-31 17:49:10 +0000606 elif authmethod is None:
Fred Drake2f8f4d32001-10-13 18:35:32 +0000607 raise SMTPException("No suitable authentication method found.")
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000608 if code not in (235, 503):
Guido van Rossumae010462001-09-11 15:57:46 +0000609 # 235 == 'Authentication successful'
610 # 503 == 'Error: already authenticated'
611 raise SMTPAuthenticationError(code, resp)
612 return (code, resp)
613
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000614 def starttls(self, keyfile=None, certfile=None):
Guido van Rossumf7fcf5e2001-09-14 16:08:44 +0000615 """Puts the connection to the SMTP server into TLS mode.
Tim Petersb64bec32001-09-18 02:26:39 +0000616
Gregory P. Smithbde4ae42008-01-17 08:35:49 +0000617 If there has been no previous EHLO or HELO command this session, this
618 method tries ESMTP EHLO first.
619
Guido van Rossumf7fcf5e2001-09-14 16:08:44 +0000620 If the server supports TLS, this will encrypt the rest of the SMTP
621 session. If you provide the keyfile and certfile parameters,
622 the identity of the SMTP server and client can be checked. This,
623 however, depends on whether the socket module really checks the
624 certificates.
Gregory P. Smithbde4ae42008-01-17 08:35:49 +0000625
626 This method may raise the following exceptions:
627
628 SMTPHeloError The server didn't reply properly to
629 the helo greeting.
Guido van Rossumf7fcf5e2001-09-14 16:08:44 +0000630 """
Gregory P. Smithbde4ae42008-01-17 08:35:49 +0000631 self.ehlo_or_helo_if_needed()
632 if not self.has_extn("starttls"):
633 raise SMTPException("STARTTLS extension not supported by server.")
Tim Petersb64bec32001-09-18 02:26:39 +0000634 (resp, reply) = self.docmd("STARTTLS")
Guido van Rossumf7fcf5e2001-09-14 16:08:44 +0000635 if resp == 220:
Bill Janssen426ea0a2007-08-29 22:35:05 +0000636 if not _have_ssl:
637 raise RuntimeError("No SSL support included in this Python")
Bill Janssen98d19da2007-09-10 21:51:02 +0000638 self.sock = ssl.wrap_socket(self.sock, keyfile, certfile)
Bill Janssen426ea0a2007-08-29 22:35:05 +0000639 self.file = SSLFakeFile(self.sock)
Gregory P. Smith63bfc1d2008-01-17 07:43:20 +0000640 # RFC 3207:
641 # The client MUST discard any knowledge obtained from
642 # the server, such as the list of SMTP service extensions,
643 # which was not obtained from the TLS negotiation itself.
644 self.helo_resp = None
645 self.ehlo_resp = None
646 self.esmtp_features = {}
647 self.does_esmtp = 0
Guido van Rossumf7fcf5e2001-09-14 16:08:44 +0000648 return (resp, reply)
Tim Petersb64bec32001-09-18 02:26:39 +0000649
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +0000650 def sendmail(self, from_addr, to_addrs, msg, mail_options=[],
Tim Peters495ad3c2001-01-15 01:36:40 +0000651 rcpt_options=[]):
652 """This command performs an entire mail transaction.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000653
Tim Peters495ad3c2001-01-15 01:36:40 +0000654 The arguments are:
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000655 - from_addr : The address sending this mail.
656 - to_addrs : A list of addresses to send this mail to. A bare
657 string will be treated as a list with 1 address.
Tim Peters495ad3c2001-01-15 01:36:40 +0000658 - msg : The message to send.
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000659 - mail_options : List of ESMTP options (such as 8bitmime) for the
660 mail command.
661 - rcpt_options : List of ESMTP options (such as DSN commands) for
662 all the rcpt commands.
663
664 If there has been no previous EHLO or HELO command this session, this
665 method tries ESMTP EHLO first. If the server does ESMTP, message size
666 and each of the specified options will be passed to it. If EHLO
667 fails, HELO will be tried and ESMTP options suppressed.
668
669 This method will return normally if the mail is accepted for at least
Barry Warsawd25c1b71999-11-28 17:11:06 +0000670 one recipient. It returns a dictionary, with one entry for each
671 recipient that was refused. Each entry contains a tuple of the SMTP
672 error code and the accompanying error message sent by the server.
Guido van Rossum296e1431999-04-07 15:03:39 +0000673
674 This method may raise the following exceptions:
675
676 SMTPHeloError The server didn't reply properly to
Tim Peters495ad3c2001-01-15 01:36:40 +0000677 the helo greeting.
Barry Warsawd25c1b71999-11-28 17:11:06 +0000678 SMTPRecipientsRefused The server rejected ALL recipients
Guido van Rossum296e1431999-04-07 15:03:39 +0000679 (no mail was sent).
680 SMTPSenderRefused The server didn't accept the from_addr.
681 SMTPDataError The server replied with an unexpected
682 error code (other than a refusal of
683 a recipient).
684
685 Note: the connection will be open even after an exception is raised.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000686
Guido van Rossum95e6f701998-06-25 02:15:50 +0000687 Example:
Tim Peters495ad3c2001-01-15 01:36:40 +0000688
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000689 >>> import smtplib
690 >>> s=smtplib.SMTP("localhost")
Guido van Rossumfc40a831998-01-29 17:26:45 +0000691 >>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]
Martin v. Löwis301b1cd2002-07-28 16:52:01 +0000692 >>> msg = '''\\
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000693 ... From: Me@my.org
694 ... Subject: testin'...
695 ...
696 ... This is a test '''
697 >>> s.sendmail("me@my.org",tolist,msg)
698 { "three@three.org" : ( 550 ,"User unknown" ) }
699 >>> s.quit()
Tim Peters495ad3c2001-01-15 01:36:40 +0000700
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000701 In the above example, the message was accepted for delivery to three
702 of the four addresses, and one was rejected, with the error code
Barry Warsawd25c1b71999-11-28 17:11:06 +0000703 550. If all addresses are accepted, then the method will return an
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000704 empty dictionary.
705
706 """
Gregory P. Smithbde4ae42008-01-17 08:35:49 +0000707 self.ehlo_or_helo_if_needed()
Guido van Rossum95e6f701998-06-25 02:15:50 +0000708 esmtp_opts = []
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000709 if self.does_esmtp:
710 # Hmmm? what's this? -ddm
711 # self.esmtp_features['7bit']=""
712 if self.has_extn('size'):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000713 esmtp_opts.append("size=%d" % len(msg))
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000714 for option in mail_options:
Guido van Rossum95e6f701998-06-25 02:15:50 +0000715 esmtp_opts.append(option)
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000716
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000717 (code, resp) = self.mail(from_addr, esmtp_opts)
Fred Drake8152d322000-12-12 23:20:45 +0000718 if code != 250:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000719 self.rset()
Guido van Rossum296e1431999-04-07 15:03:39 +0000720 raise SMTPSenderRefused(code, resp, from_addr)
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000721 senderrs = {}
Walter Dörwald65230a22002-06-03 15:58:32 +0000722 if isinstance(to_addrs, basestring):
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +0000723 to_addrs = [to_addrs]
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000724 for each in to_addrs:
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000725 (code, resp) = self.rcpt(each, rcpt_options)
Fred Drake8152d322000-12-12 23:20:45 +0000726 if (code != 250) and (code != 251):
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000727 senderrs[each] = (code, resp)
728 if len(senderrs) == len(to_addrs):
Guido van Rossum95e6f701998-06-25 02:15:50 +0000729 # the server refused all our recipients
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000730 self.rset()
Guido van Rossum296e1431999-04-07 15:03:39 +0000731 raise SMTPRecipientsRefused(senderrs)
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000732 (code, resp) = self.data(msg)
Fred Drake8152d322000-12-12 23:20:45 +0000733 if code != 250:
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000734 self.rset()
Guido van Rossum296e1431999-04-07 15:03:39 +0000735 raise SMTPDataError(code, resp)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000736 #if we got here then somebody got our mail
Tim Peters495ad3c2001-01-15 01:36:40 +0000737 return senderrs
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000738
739
740 def close(self):
741 """Close the connection to the SMTP server."""
742 if self.file:
743 self.file.close()
744 self.file = None
745 if self.sock:
746 self.sock.close()
747 self.sock = None
748
749
750 def quit(self):
Guido van Rossum95e6f701998-06-25 02:15:50 +0000751 """Terminate the SMTP session."""
Georg Brandldeaf2ca2008-03-27 13:27:31 +0000752 res = self.docmd("quit")
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000753 self.close()
Georg Brandldeaf2ca2008-03-27 13:27:31 +0000754 return res
Guido van Rossum95e6f701998-06-25 02:15:50 +0000755
Bill Janssen426ea0a2007-08-29 22:35:05 +0000756if _have_ssl:
Martin v. Löwisee82c0e2006-10-27 07:13:28 +0000757
Bill Janssen426ea0a2007-08-29 22:35:05 +0000758 class SMTP_SSL(SMTP):
759 """ This is a subclass derived from SMTP that connects over an SSL encrypted
760 socket (to use this class you need a socket module that was compiled with SSL
761 support). If host is not specified, '' (the local host) is used. If port is
762 omitted, the standard SMTP-over-SSL port (465) is used. keyfile and certfile
763 are also optional - they can contain a PEM formatted private key and
764 certificate chain file for the SSL connection.
765 """
Antoine Pitrou21ce8f02011-05-07 19:59:33 +0200766
767 default_port = SMTP_SSL_PORT
768
Bill Janssen426ea0a2007-08-29 22:35:05 +0000769 def __init__(self, host='', port=0, local_hostname=None,
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000770 keyfile=None, certfile=None,
771 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Bill Janssen426ea0a2007-08-29 22:35:05 +0000772 self.keyfile = keyfile
773 self.certfile = certfile
774 SMTP.__init__(self, host, port, local_hostname, timeout)
Bill Janssen426ea0a2007-08-29 22:35:05 +0000775
776 def _get_socket(self, host, port, timeout):
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000777 if self.debuglevel > 0:
778 print>>stderr, 'connect:', (host, port)
R. David Murrayad3058e2009-05-23 00:48:58 +0000779 new_socket = socket.create_connection((host, port), timeout)
780 new_socket = ssl.wrap_socket(new_socket, self.keyfile, self.certfile)
781 self.file = SSLFakeFile(new_socket)
782 return new_socket
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000783
Thomas Woutersa6900e82007-08-30 21:54:39 +0000784 __all__.append("SMTP_SSL")
785
Martin v. Löwis1190a382007-03-09 15:35:55 +0000786#
787# LMTP extension
788#
789LMTP_PORT = 2003
790
791class LMTP(SMTP):
792 """LMTP - Local Mail Transfer Protocol
793
794 The LMTP protocol, which is very similar to ESMTP, is heavily based
795 on the standard SMTP client. It's common to use Unix sockets for LMTP,
796 so our connect() method must support that as well as a regular
797 host:port server. To specify a Unix socket, you must use an absolute
798 path as the host, starting with a '/'.
799
800 Authentication is supported, using the regular SMTP mechanism. When
801 using a Unix socket, LMTP generally don't support or require any
802 authentication, but your mileage might vary."""
803
804 ehlo_msg = "lhlo"
Tim Petersea5962f2007-03-12 18:07:52 +0000805
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000806 def __init__(self, host='', port=LMTP_PORT, local_hostname=None):
Martin v. Löwis1190a382007-03-09 15:35:55 +0000807 """Initialize a new instance."""
808 SMTP.__init__(self, host, port, local_hostname)
809
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000810 def connect(self, host='localhost', port=0):
Martin v. Löwis1190a382007-03-09 15:35:55 +0000811 """Connect to the LMTP daemon, on either a Unix or a TCP socket."""
Neal Norwitzc8f6c232007-03-10 03:19:18 +0000812 if host[0] != '/':
Martin v. Löwis1190a382007-03-09 15:35:55 +0000813 return SMTP.connect(self, host, port)
814
Neal Norwitzc8f6c232007-03-10 03:19:18 +0000815 # Handle Unix-domain sockets.
816 try:
817 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
818 self.sock.connect(host)
819 except socket.error, msg:
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000820 if self.debuglevel > 0:
821 print>>stderr, 'connect fail:', host
Neal Norwitzc8f6c232007-03-10 03:19:18 +0000822 if self.sock:
823 self.sock.close()
824 self.sock = None
825 raise socket.error, msg
826 (code, msg) = self.getreply()
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000827 if self.debuglevel > 0:
828 print>>stderr, "connect:", msg
Neal Norwitzc8f6c232007-03-10 03:19:18 +0000829 return (code, msg)
830
Martin v. Löwis1190a382007-03-09 15:35:55 +0000831
Guido van Rossum95e6f701998-06-25 02:15:50 +0000832# Test the sendmail method, which tests most of the others.
833# Note: This always sends to localhost.
834if __name__ == '__main__':
Andrew M. Kuchling6be424f2001-08-13 14:41:39 +0000835 import sys
Guido van Rossum95e6f701998-06-25 02:15:50 +0000836
837 def prompt(prompt):
838 sys.stdout.write(prompt + ": ")
Eric S. Raymondc013f302001-02-09 05:40:38 +0000839 return sys.stdin.readline().strip()
Guido van Rossum95e6f701998-06-25 02:15:50 +0000840
841 fromaddr = prompt("From")
Giampaolo Rodolà5c12ec62011-02-24 20:43:11 +0000842 toaddrs = prompt("To").split(',')
Guido van Rossum95e6f701998-06-25 02:15:50 +0000843 print "Enter message, end with ^D:"
844 msg = ''
845 while 1:
846 line = sys.stdin.readline()
847 if not line:
848 break
849 msg = msg + line
Walter Dörwald70a6b492004-02-12 17:35:32 +0000850 print "Message length is %d" % len(msg)
Guido van Rossum95e6f701998-06-25 02:15:50 +0000851
852 server = SMTP('localhost')
853 server.set_debuglevel(1)
854 server.sendmail(fromaddr, toaddrs, msg)
855 server.quit()