blob: 1af406883a5c51e8d67a457048507f2e87143025 [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 Rossum95e6f701998-06-25 02:15:50 +00005This should follow RFC 821 (SMTP) and RFC 1869 (ESMTP).
Guido van Rossumbbe323e1998-01-29 17:24:40 +00006
Guido van Rossumfcfb6321998-08-04 15:29:54 +00007Notes:
8
9Please remember, when doing ESMTP, that the names of the SMTP service
Barry Warsaw4c4bec81998-12-22 03:02:20 +000010extensions are NOT the same thing as the option keywords for the RCPT
Guido van Rossumfcfb6321998-08-04 15:29:54 +000011and MAIL commands!
12
Guido van Rossumbbe323e1998-01-29 17:24:40 +000013Example:
14
Barry Warsawa7d9bdf1998-12-22 03:24:27 +000015 >>> import smtplib
16 >>> s=smtplib.SMTP("localhost")
17 >>> print s.help()
18 This is Sendmail version 8.8.4
19 Topics:
20 HELO EHLO MAIL RCPT DATA
21 RSET NOOP QUIT HELP VRFY
22 EXPN VERB ETRN DSN
23 For more info use "HELP <topic>".
24 To report bugs in the implementation send email to
25 sendmail-bugs@sendmail.org.
26 For local information send email to Postmaster at your site.
27 End of HELP info
28 >>> s.putcmd("vrfy","someone@here")
29 >>> s.getreply()
30 (250, "Somebody OverHere <somebody@here.my.org>")
31 >>> s.quit()
Barry Warsawa1ae8842000-07-09 21:24:31 +000032'''
Guido van Rossumbbe323e1998-01-29 17:24:40 +000033
Guido van Rossum98d9fd32000-02-28 15:12:25 +000034# Author: The Dragon De Monsyne <dragondm@integral.org>
35# ESMTP support, test code and doc fixes added by
36# Eric S. Raymond <esr@thyrsus.com>
37# Better RFC 821 compliance (MAIL and RCPT, and CRLF in data)
38# by Carey Evans <c.evans@clear.net.nz>, for picky mail servers.
Tim Peters495ad3c2001-01-15 01:36:40 +000039#
Guido van Rossum98d9fd32000-02-28 15:12:25 +000040# This was modified from the Python 1.5 library HTTP lib.
41
Guido van Rossumbbe323e1998-01-29 17:24:40 +000042import socket
Barry Warsaw07201771998-12-22 20:37:36 +000043import re
Guido van Rossumfcfb6321998-08-04 15:29:54 +000044import rfc822
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +000045import types
Guido van Rossumbbe323e1998-01-29 17:24:40 +000046
47SMTP_PORT = 25
48CRLF="\r\n"
49
Tim Peters495ad3c2001-01-15 01:36:40 +000050# Exception classes used by this module.
Guido van Rossum296e1431999-04-07 15:03:39 +000051class SMTPException(Exception):
52 """Base class for all exceptions raised by this module."""
53
54class SMTPServerDisconnected(SMTPException):
55 """Not connected to any SMTP server.
56
57 This exception is raised when the server unexpectedly disconnects,
58 or when an attempt is made to use the SMTP instance before
59 connecting it to a server.
60 """
61
62class SMTPResponseException(SMTPException):
63 """Base class for all exceptions that include an SMTP error code.
64
65 These exceptions are generated in some instances when the SMTP
66 server returns an error code. The error code is stored in the
67 `smtp_code' attribute of the error, and the `smtp_error' attribute
68 is set to the error message.
69 """
70
71 def __init__(self, code, msg):
72 self.smtp_code = code
73 self.smtp_error = msg
74 self.args = (code, msg)
75
76class SMTPSenderRefused(SMTPResponseException):
77 """Sender address refused.
78 In addition to the attributes set by on all SMTPResponseException
Barry Warsawd25c1b71999-11-28 17:11:06 +000079 exceptions, this sets `sender' to the string that the SMTP refused.
Guido van Rossum296e1431999-04-07 15:03:39 +000080 """
81
82 def __init__(self, code, msg, sender):
83 self.smtp_code = code
84 self.smtp_error = msg
85 self.sender = sender
86 self.args = (code, msg, sender)
87
Guido van Rossum20c92281999-04-21 16:52:20 +000088class SMTPRecipientsRefused(SMTPException):
Barry Warsawd25c1b71999-11-28 17:11:06 +000089 """All recipient addresses refused.
Thomas Wouters7e474022000-07-16 12:04:32 +000090 The errors for each recipient are accessible through the attribute
Tim Peters495ad3c2001-01-15 01:36:40 +000091 'recipients', which is a dictionary of exactly the same sort as
92 SMTP.sendmail() returns.
Guido van Rossum296e1431999-04-07 15:03:39 +000093 """
94
95 def __init__(self, recipients):
96 self.recipients = recipients
97 self.args = ( recipients,)
98
99
Guido van Rossum296e1431999-04-07 15:03:39 +0000100class SMTPDataError(SMTPResponseException):
101 """The SMTP server didn't accept the data."""
102
103class SMTPConnectError(SMTPResponseException):
Barry Warsawd25c1b71999-11-28 17:11:06 +0000104 """Error during connection establishment."""
Guido van Rossum296e1431999-04-07 15:03:39 +0000105
106class SMTPHeloError(SMTPResponseException):
Barry Warsawd25c1b71999-11-28 17:11:06 +0000107 """The server refused our HELO reply."""
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000108
Peter Schneider-Kamp7bc82bb2000-08-10 14:02:23 +0000109
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000110def quoteaddr(addr):
111 """Quote a subset of the email addresses defined by RFC 821.
112
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000113 Should be able to handle anything rfc822.parseaddr can handle.
114 """
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000115 m=None
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000116 try:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000117 m=rfc822.parseaddr(addr)[1]
118 except AttributeError:
119 pass
120 if not m:
121 #something weird here.. punt -ddm
122 return addr
123 else:
124 return "<%s>" % m
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000125
126def quotedata(data):
127 """Quote data for email.
128
Barry Warsawd25c1b71999-11-28 17:11:06 +0000129 Double leading '.', and change Unix newline '\\n', or Mac '\\r' into
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000130 Internet CRLF end-of-line.
131 """
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000132 return re.sub(r'(?m)^\.', '..',
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000133 re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data))
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000134
Peter Schneider-Kamp7bc82bb2000-08-10 14:02:23 +0000135
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000136class SMTP:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000137 """This class manages a connection to an SMTP or ESMTP server.
138 SMTP Objects:
Tim Peters495ad3c2001-01-15 01:36:40 +0000139 SMTP objects have the following attributes:
140 helo_resp
141 This is the message given by the server in response to the
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000142 most recent HELO command.
Tim Peters495ad3c2001-01-15 01:36:40 +0000143
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000144 ehlo_resp
Tim Peters495ad3c2001-01-15 01:36:40 +0000145 This is the message given by the server in response to the
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000146 most recent EHLO command. This is usually multiline.
147
Tim Peters495ad3c2001-01-15 01:36:40 +0000148 does_esmtp
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000149 This is a True value _after you do an EHLO command_, if the
150 server supports ESMTP.
151
Tim Peters495ad3c2001-01-15 01:36:40 +0000152 esmtp_features
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000153 This is a dictionary, which, if the server supports ESMTP,
Barry Warsawd25c1b71999-11-28 17:11:06 +0000154 will _after you do an EHLO command_, contain the names of the
155 SMTP service extensions this server supports, and their
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000156 parameters (if any).
Barry Warsawd25c1b71999-11-28 17:11:06 +0000157
Tim Peters495ad3c2001-01-15 01:36:40 +0000158 Note, all extension names are mapped to lower case in the
159 dictionary.
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000160
Barry Warsawd25c1b71999-11-28 17:11:06 +0000161 See each method's docstrings for details. In general, there is a
162 method of the same name to perform each SMTP command. There is also a
163 method called 'sendmail' that will do an entire mail transaction.
164 """
Guido van Rossum95e6f701998-06-25 02:15:50 +0000165 debuglevel = 0
166 file = None
167 helo_resp = None
168 ehlo_resp = None
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000169 does_esmtp = 0
Guido van Rossum95e6f701998-06-25 02:15:50 +0000170
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000171 def __init__(self, host = '', port = 0):
172 """Initialize a new instance.
173
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000174 If specified, `host' is the name of the remote host to which to
175 connect. If specified, `port' specifies the port to which to connect.
Barry Warsawd25c1b71999-11-28 17:11:06 +0000176 By default, smtplib.SMTP_PORT is used. An SMTPConnectError is raised
177 if the specified `host' doesn't respond correctly.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000178
179 """
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000180 self.esmtp_features = {}
Guido van Rossum296e1431999-04-07 15:03:39 +0000181 if host:
182 (code, msg) = self.connect(host, port)
183 if code != 220:
184 raise SMTPConnectError(code, msg)
Tim Peters495ad3c2001-01-15 01:36:40 +0000185
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000186 def set_debuglevel(self, debuglevel):
187 """Set the debug output level.
188
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000189 A non-false value results in debug messages for connection and for all
190 messages sent to and received from the server.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000191
192 """
193 self.debuglevel = debuglevel
194
195 def connect(self, host='localhost', port = 0):
196 """Connect to a host on a given port.
Guido van Rossum95e6f701998-06-25 02:15:50 +0000197
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000198 If the hostname ends with a colon (`:') followed by a number, and
199 there is no port specified, that suffix will be stripped off and the
200 number interpreted as the port number to use.
Guido van Rossum95e6f701998-06-25 02:15:50 +0000201
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000202 Note: This method is automatically invoked by __init__, if a host is
203 specified during instantiation.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000204
205 """
206 if not port:
Eric S. Raymondc013f302001-02-09 05:40:38 +0000207 i = host.find(':')
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000208 if i >= 0:
209 host, port = host[:i], host[i+1:]
Eric S. Raymondc013f302001-02-09 05:40:38 +0000210 try: port = int(port)
Eric S. Raymond8d876032001-02-09 10:14:53 +0000211 except ValueError:
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000212 raise socket.error, "nonnumeric port"
213 if not port: port = SMTP_PORT
214 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
215 if self.debuglevel > 0: print 'connect:', (host, port)
Barry Warsaw17bfef52000-11-08 22:19:47 +0000216 try:
217 self.sock.connect((host, port))
218 except socket.error:
219 self.close()
220 raise
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000221 (code,msg)=self.getreply()
222 if self.debuglevel >0 : print "connect:", msg
Guido van Rossum296e1431999-04-07 15:03:39 +0000223 return (code,msg)
Tim Peters495ad3c2001-01-15 01:36:40 +0000224
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000225 def send(self, str):
226 """Send `str' to the server."""
227 if self.debuglevel > 0: print 'send:', `str`
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000228 if self.sock:
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000229 try:
Barry Warsaw5bf94a02000-09-01 06:40:07 +0000230 sendptr = 0
231 while sendptr < len(str):
232 sendptr = sendptr + self.sock.send(str[sendptr:])
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000233 except socket.error:
Guido van Rossum40233ea1999-01-15 03:23:55 +0000234 raise SMTPServerDisconnected('Server not connected')
Guido van Rossumfc40a831998-01-29 17:26:45 +0000235 else:
Guido van Rossum40233ea1999-01-15 03:23:55 +0000236 raise SMTPServerDisconnected('please run connect() first')
Tim Peters495ad3c2001-01-15 01:36:40 +0000237
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000238 def putcmd(self, cmd, args=""):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000239 """Send a command to the server."""
Guido van Rossumdb23d3d1999-06-09 15:13:10 +0000240 if args == "":
241 str = '%s%s' % (cmd, CRLF)
242 else:
243 str = '%s %s%s' % (cmd, args, CRLF)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000244 self.send(str)
Tim Peters495ad3c2001-01-15 01:36:40 +0000245
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000246 def getreply(self):
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000247 """Get a reply from the server.
Tim Peters495ad3c2001-01-15 01:36:40 +0000248
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000249 Returns a tuple consisting of:
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000250
251 - server response code (e.g. '250', or such, if all goes well)
252 Note: returns -1 if it can't read response code.
253
254 - server response string corresponding to response code (multiline
255 responses are converted to a single, multiline string).
Guido van Rossumf123f841999-03-29 20:33:21 +0000256
257 Raises SMTPServerDisconnected if end-of-file is reached.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000258 """
259 resp=[]
Guido van Rossum296e1431999-04-07 15:03:39 +0000260 if self.file is None:
261 self.file = self.sock.makefile('rb')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000262 while 1:
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000263 line = self.file.readline()
Guido van Rossum296e1431999-04-07 15:03:39 +0000264 if line == '':
265 self.close()
266 raise SMTPServerDisconnected("Connection unexpectedly closed")
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000267 if self.debuglevel > 0: print 'reply:', `line`
Eric S. Raymondc013f302001-02-09 05:40:38 +0000268 resp.append(line[4:].strip())
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000269 code=line[:3]
Guido van Rossum296e1431999-04-07 15:03:39 +0000270 # Check that the error code is syntactically correct.
271 # Don't attempt to read a continuation line if it is broken.
272 try:
Eric S. Raymondc013f302001-02-09 05:40:38 +0000273 errcode = int(code)
Guido van Rossum296e1431999-04-07 15:03:39 +0000274 except ValueError:
275 errcode = -1
276 break
Guido van Rossumf123f841999-03-29 20:33:21 +0000277 # Check if multiline response.
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000278 if line[3:4]!="-":
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000279 break
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000280
Eric S. Raymondc013f302001-02-09 05:40:38 +0000281 errmsg = "\n".join(resp)
Tim Peters495ad3c2001-01-15 01:36:40 +0000282 if self.debuglevel > 0:
Guido van Rossumfc40a831998-01-29 17:26:45 +0000283 print 'reply: retcode (%s); Msg: %s' % (errcode,errmsg)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000284 return errcode, errmsg
Tim Peters495ad3c2001-01-15 01:36:40 +0000285
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000286 def docmd(self, cmd, args=""):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000287 """Send a command, and return its response code."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000288 self.putcmd(cmd,args)
Guido van Rossum296e1431999-04-07 15:03:39 +0000289 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000290
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000291 # std smtp commands
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000292 def helo(self, name=''):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000293 """SMTP 'helo' command.
294 Hostname to send for this command defaults to the FQDN of the local
295 host.
296 """
Thomas Wouterscaa658d2000-08-15 19:30:36 +0000297 if name:
298 self.putcmd("helo", name)
299 else:
Fred Drake0ebc1c62000-08-16 14:26:22 +0000300 self.putcmd("helo", socket.getfqdn())
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000301 (code,msg)=self.getreply()
302 self.helo_resp=msg
Guido van Rossum296e1431999-04-07 15:03:39 +0000303 return (code,msg)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000304
Guido van Rossum95e6f701998-06-25 02:15:50 +0000305 def ehlo(self, name=''):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000306 """ SMTP 'ehlo' command.
307 Hostname to send for this command defaults to the FQDN of the local
308 host.
309 """
Thomas Wouterscaa658d2000-08-15 19:30:36 +0000310 if name:
311 self.putcmd("ehlo", name)
312 else:
Fred Drake0ebc1c62000-08-16 14:26:22 +0000313 self.putcmd("ehlo", socket.getfqdn())
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000314 (code,msg)=self.getreply()
Tim Peters495ad3c2001-01-15 01:36:40 +0000315 # According to RFC1869 some (badly written)
316 # MTA's will disconnect on an ehlo. Toss an exception if
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000317 # that happens -ddm
318 if code == -1 and len(msg) == 0:
Guido van Rossum40233ea1999-01-15 03:23:55 +0000319 raise SMTPServerDisconnected("Server not connected")
Guido van Rossum95e6f701998-06-25 02:15:50 +0000320 self.ehlo_resp=msg
Fred Drake8152d322000-12-12 23:20:45 +0000321 if code != 250:
Guido van Rossum296e1431999-04-07 15:03:39 +0000322 return (code,msg)
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000323 self.does_esmtp=1
Thomas Wouters7e474022000-07-16 12:04:32 +0000324 #parse the ehlo response -ddm
Eric S. Raymondc013f302001-02-09 05:40:38 +0000325 resp=self.ehlo_resp.split('\n')
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000326 del resp[0]
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000327 for each in resp:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000328 m=re.match(r'(?P<feature>[A-Za-z0-9][A-Za-z0-9\-]*)',each)
329 if m:
Eric S. Raymondc013f302001-02-09 05:40:38 +0000330 feature=m.group("feature").lower()
331 params=m.string[m.end("feature"):].strip()
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000332 self.esmtp_features[feature]=params
Guido van Rossum296e1431999-04-07 15:03:39 +0000333 return (code,msg)
Guido van Rossum95e6f701998-06-25 02:15:50 +0000334
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000335 def has_extn(self, opt):
336 """Does the server support a given SMTP service extension?"""
Eric S. Raymondc013f302001-02-09 05:40:38 +0000337 return self.esmtp_features.has_key(opt.lower())
Guido van Rossum95e6f701998-06-25 02:15:50 +0000338
Guido van Rossum18586f41998-04-03 17:03:13 +0000339 def help(self, args=''):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000340 """SMTP 'help' command.
341 Returns help text from server."""
Guido van Rossum18586f41998-04-03 17:03:13 +0000342 self.putcmd("help", args)
Guido van Rossum296e1431999-04-07 15:03:39 +0000343 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000344
345 def rset(self):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000346 """SMTP 'rset' command -- resets session."""
Guido van Rossum296e1431999-04-07 15:03:39 +0000347 return self.docmd("rset")
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000348
349 def noop(self):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000350 """SMTP 'noop' command -- doesn't do anything :>"""
Guido van Rossum296e1431999-04-07 15:03:39 +0000351 return self.docmd("noop")
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000352
Guido van Rossum95e6f701998-06-25 02:15:50 +0000353 def mail(self,sender,options=[]):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000354 """SMTP 'mail' command -- begins mail xfer session."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000355 optionlist = ''
356 if options and self.does_esmtp:
Eric S. Raymondc013f302001-02-09 05:40:38 +0000357 optionlist = ' ' + ' '.join(options)
Guido van Rossumdb23d3d1999-06-09 15:13:10 +0000358 self.putcmd("mail", "FROM:%s%s" % (quoteaddr(sender) ,optionlist))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000359 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000360
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000361 def rcpt(self,recip,options=[]):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000362 """SMTP 'rcpt' command -- indicates 1 recipient for this mail."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000363 optionlist = ''
364 if options and self.does_esmtp:
Eric S. Raymondc013f302001-02-09 05:40:38 +0000365 optionlist = ' ' + ' '.join(options)
Guido van Rossum348fd061999-01-14 04:18:46 +0000366 self.putcmd("rcpt","TO:%s%s" % (quoteaddr(recip),optionlist))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000367 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000368
369 def data(self,msg):
Tim Peters495ad3c2001-01-15 01:36:40 +0000370 """SMTP 'DATA' command -- sends message data to server.
Guido van Rossum296e1431999-04-07 15:03:39 +0000371
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000372 Automatically quotes lines beginning with a period per rfc821.
Guido van Rossum296e1431999-04-07 15:03:39 +0000373 Raises SMTPDataError if there is an unexpected reply to the
374 DATA command; the return value from this method is the final
375 response code received when the all data is sent.
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000376 """
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000377 self.putcmd("data")
378 (code,repl)=self.getreply()
379 if self.debuglevel >0 : print "data:", (code,repl)
Fred Drake8152d322000-12-12 23:20:45 +0000380 if code != 354:
Guido van Rossum296e1431999-04-07 15:03:39 +0000381 raise SMTPDataError(code,repl)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000382 else:
Guido van Rossum20c92281999-04-21 16:52:20 +0000383 q = quotedata(msg)
384 if q[-2:] != CRLF:
385 q = q + CRLF
386 q = q + "." + CRLF
387 self.send(q)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000388 (code,msg)=self.getreply()
389 if self.debuglevel >0 : print "data:", (code,msg)
Guido van Rossum296e1431999-04-07 15:03:39 +0000390 return (code,msg)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000391
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000392 def verify(self, address):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000393 """SMTP 'verify' command -- checks for address validity."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000394 self.putcmd("vrfy", quoteaddr(address))
395 return self.getreply()
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000396 # a.k.a.
397 vrfy=verify
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000398
399 def expn(self, address):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000400 """SMTP 'verify' command -- checks for address validity."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000401 self.putcmd("expn", quoteaddr(address))
402 return self.getreply()
403
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000404 # some useful methods
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +0000405 def sendmail(self, from_addr, to_addrs, msg, mail_options=[],
Tim Peters495ad3c2001-01-15 01:36:40 +0000406 rcpt_options=[]):
407 """This command performs an entire mail transaction.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000408
Tim Peters495ad3c2001-01-15 01:36:40 +0000409 The arguments are:
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000410 - from_addr : The address sending this mail.
411 - to_addrs : A list of addresses to send this mail to. A bare
412 string will be treated as a list with 1 address.
Tim Peters495ad3c2001-01-15 01:36:40 +0000413 - msg : The message to send.
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000414 - mail_options : List of ESMTP options (such as 8bitmime) for the
415 mail command.
416 - rcpt_options : List of ESMTP options (such as DSN commands) for
417 all the rcpt commands.
418
419 If there has been no previous EHLO or HELO command this session, this
420 method tries ESMTP EHLO first. If the server does ESMTP, message size
421 and each of the specified options will be passed to it. If EHLO
422 fails, HELO will be tried and ESMTP options suppressed.
423
424 This method will return normally if the mail is accepted for at least
Barry Warsawd25c1b71999-11-28 17:11:06 +0000425 one recipient. It returns a dictionary, with one entry for each
426 recipient that was refused. Each entry contains a tuple of the SMTP
427 error code and the accompanying error message sent by the server.
Guido van Rossum296e1431999-04-07 15:03:39 +0000428
429 This method may raise the following exceptions:
430
431 SMTPHeloError The server didn't reply properly to
Tim Peters495ad3c2001-01-15 01:36:40 +0000432 the helo greeting.
Barry Warsawd25c1b71999-11-28 17:11:06 +0000433 SMTPRecipientsRefused The server rejected ALL recipients
Guido van Rossum296e1431999-04-07 15:03:39 +0000434 (no mail was sent).
435 SMTPSenderRefused The server didn't accept the from_addr.
436 SMTPDataError The server replied with an unexpected
437 error code (other than a refusal of
438 a recipient).
439
440 Note: the connection will be open even after an exception is raised.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000441
Guido van Rossum95e6f701998-06-25 02:15:50 +0000442 Example:
Tim Peters495ad3c2001-01-15 01:36:40 +0000443
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000444 >>> import smtplib
445 >>> s=smtplib.SMTP("localhost")
Guido van Rossumfc40a831998-01-29 17:26:45 +0000446 >>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000447 >>> msg = '''
448 ... From: Me@my.org
449 ... Subject: testin'...
450 ...
451 ... This is a test '''
452 >>> s.sendmail("me@my.org",tolist,msg)
453 { "three@three.org" : ( 550 ,"User unknown" ) }
454 >>> s.quit()
Tim Peters495ad3c2001-01-15 01:36:40 +0000455
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000456 In the above example, the message was accepted for delivery to three
457 of the four addresses, and one was rejected, with the error code
Barry Warsawd25c1b71999-11-28 17:11:06 +0000458 550. If all addresses are accepted, then the method will return an
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000459 empty dictionary.
460
461 """
Guido van Rossum296e1431999-04-07 15:03:39 +0000462 if self.helo_resp is None and self.ehlo_resp is None:
463 if not (200 <= self.ehlo()[0] <= 299):
464 (code,resp) = self.helo()
465 if not (200 <= code <= 299):
466 raise SMTPHeloError(code, resp)
Guido van Rossum95e6f701998-06-25 02:15:50 +0000467 esmtp_opts = []
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000468 if self.does_esmtp:
469 # Hmmm? what's this? -ddm
470 # self.esmtp_features['7bit']=""
471 if self.has_extn('size'):
472 esmtp_opts.append("size=" + `len(msg)`)
473 for option in mail_options:
Guido van Rossum95e6f701998-06-25 02:15:50 +0000474 esmtp_opts.append(option)
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000475
Guido van Rossum95e6f701998-06-25 02:15:50 +0000476 (code,resp) = self.mail(from_addr, esmtp_opts)
Fred Drake8152d322000-12-12 23:20:45 +0000477 if code != 250:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000478 self.rset()
Guido van Rossum296e1431999-04-07 15:03:39 +0000479 raise SMTPSenderRefused(code, resp, from_addr)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000480 senderrs={}
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +0000481 if type(to_addrs) == types.StringType:
482 to_addrs = [to_addrs]
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000483 for each in to_addrs:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000484 (code,resp)=self.rcpt(each, rcpt_options)
Fred Drake8152d322000-12-12 23:20:45 +0000485 if (code != 250) and (code != 251):
Guido van Rossumfc40a831998-01-29 17:26:45 +0000486 senderrs[each]=(code,resp)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000487 if len(senderrs)==len(to_addrs):
Guido van Rossum95e6f701998-06-25 02:15:50 +0000488 # the server refused all our recipients
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000489 self.rset()
Guido van Rossum296e1431999-04-07 15:03:39 +0000490 raise SMTPRecipientsRefused(senderrs)
Fred Drake8152d322000-12-12 23:20:45 +0000491 (code,resp) = self.data(msg)
492 if code != 250:
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000493 self.rset()
Guido van Rossum296e1431999-04-07 15:03:39 +0000494 raise SMTPDataError(code, resp)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000495 #if we got here then somebody got our mail
Tim Peters495ad3c2001-01-15 01:36:40 +0000496 return senderrs
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000497
498
499 def close(self):
500 """Close the connection to the SMTP server."""
501 if self.file:
502 self.file.close()
503 self.file = None
504 if self.sock:
505 self.sock.close()
506 self.sock = None
507
508
509 def quit(self):
Guido van Rossum95e6f701998-06-25 02:15:50 +0000510 """Terminate the SMTP session."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000511 self.docmd("quit")
512 self.close()
Guido van Rossum95e6f701998-06-25 02:15:50 +0000513
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000514
Guido van Rossum95e6f701998-06-25 02:15:50 +0000515# Test the sendmail method, which tests most of the others.
516# Note: This always sends to localhost.
517if __name__ == '__main__':
518 import sys, rfc822
519
520 def prompt(prompt):
521 sys.stdout.write(prompt + ": ")
Eric S. Raymondc013f302001-02-09 05:40:38 +0000522 return sys.stdin.readline().strip()
Guido van Rossum95e6f701998-06-25 02:15:50 +0000523
524 fromaddr = prompt("From")
Eric S. Raymond38151ed2001-02-09 07:40:17 +0000525 toaddrs = prompt("To").split(',')
Guido van Rossum95e6f701998-06-25 02:15:50 +0000526 print "Enter message, end with ^D:"
527 msg = ''
528 while 1:
529 line = sys.stdin.readline()
530 if not line:
531 break
532 msg = msg + line
533 print "Message length is " + `len(msg)`
534
535 server = SMTP('localhost')
536 server.set_debuglevel(1)
537 server.sendmail(fromaddr, toaddrs, msg)
538 server.quit()