blob: d955e696cf3475c86fe9777026a482f40c238773 [file] [log] [blame]
Barry Warsaw4c4bec81998-12-22 03:02:20 +00001#! /usr/bin/env python
2
3'''SMTP/ESMTP client class.
Guido van Rossumbbe323e1998-01-29 17:24:40 +00004
5Author: The Dragon De Monsyne <dragondm@integral.org>
Guido van Rossum95e6f701998-06-25 02:15:50 +00006ESMTP support, test code and doc fixes added by
Guido van Rossumfcfb6321998-08-04 15:29:54 +00007 Eric S. Raymond <esr@thyrsus.com>
Guido van Rossum69a79bc1998-07-13 15:18:49 +00008Better RFC 821 compliance (MAIL and RCPT, and CRLF in data)
Guido van Rossumfcfb6321998-08-04 15:29:54 +00009 by Carey Evans <c.evans@clear.net.nz>, for picky mail servers.
10
Barry Warsawa7d9bdf1998-12-22 03:24:27 +000011This was modified from the Python 1.5 library HTTP lib.
Guido van Rossumbbe323e1998-01-29 17:24:40 +000012
Guido van Rossum95e6f701998-06-25 02:15:50 +000013This should follow RFC 821 (SMTP) and RFC 1869 (ESMTP).
Guido van Rossumbbe323e1998-01-29 17:24:40 +000014
Guido van Rossumfcfb6321998-08-04 15:29:54 +000015Notes:
16
17Please remember, when doing ESMTP, that the names of the SMTP service
Barry Warsaw4c4bec81998-12-22 03:02:20 +000018extensions are NOT the same thing as the option keywords for the RCPT
Guido van Rossumfcfb6321998-08-04 15:29:54 +000019and MAIL commands!
20
Guido van Rossumbbe323e1998-01-29 17:24:40 +000021Example:
22
Barry Warsawa7d9bdf1998-12-22 03:24:27 +000023 >>> import smtplib
24 >>> s=smtplib.SMTP("localhost")
25 >>> print s.help()
26 This is Sendmail version 8.8.4
27 Topics:
28 HELO EHLO MAIL RCPT DATA
29 RSET NOOP QUIT HELP VRFY
30 EXPN VERB ETRN DSN
31 For more info use "HELP <topic>".
32 To report bugs in the implementation send email to
33 sendmail-bugs@sendmail.org.
34 For local information send email to Postmaster at your site.
35 End of HELP info
36 >>> s.putcmd("vrfy","someone@here")
37 >>> s.getreply()
38 (250, "Somebody OverHere <somebody@here.my.org>")
39 >>> s.quit()
Guido van Rossumbbe323e1998-01-29 17:24:40 +000040
Barry Warsaw4c4bec81998-12-22 03:02:20 +000041'''
Guido van Rossumbbe323e1998-01-29 17:24:40 +000042
43import socket
Guido van Rossumfcfb6321998-08-04 15:29:54 +000044import string, re
45import rfc822
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +000046import types
Guido van Rossumbbe323e1998-01-29 17:24:40 +000047
48SMTP_PORT = 25
49CRLF="\r\n"
50
51# used for exceptions
Guido van Rossumfc40a831998-01-29 17:26:45 +000052SMTPServerDisconnected="Server not connected"
Guido van Rossumbbe323e1998-01-29 17:24:40 +000053SMTPSenderRefused="Sender address refused"
54SMTPRecipientsRefused="All Recipients refused"
Guido van Rossum95e6f701998-06-25 02:15:50 +000055SMTPDataError="Error transmitting message data"
Guido van Rossumbbe323e1998-01-29 17:24:40 +000056
Guido van Rossum69a79bc1998-07-13 15:18:49 +000057def quoteaddr(addr):
58 """Quote a subset of the email addresses defined by RFC 821.
59
Barry Warsawa7d9bdf1998-12-22 03:24:27 +000060 Should be able to handle anything rfc822.parseaddr can handle.
61 """
Guido van Rossumfcfb6321998-08-04 15:29:54 +000062 m=None
Guido van Rossum69a79bc1998-07-13 15:18:49 +000063 try:
Guido van Rossumfcfb6321998-08-04 15:29:54 +000064 m=rfc822.parseaddr(addr)[1]
65 except AttributeError:
66 pass
67 if not m:
68 #something weird here.. punt -ddm
69 return addr
70 else:
71 return "<%s>" % m
Guido van Rossum69a79bc1998-07-13 15:18:49 +000072
73def quotedata(data):
74 """Quote data for email.
75
Guido van Rossumfcfb6321998-08-04 15:29:54 +000076 Double leading '.', and change Unix newline '\n', or Mac '\r' into
Barry Warsawa7d9bdf1998-12-22 03:24:27 +000077 Internet CRLF end-of-line.
78 """
Guido van Rossum69a79bc1998-07-13 15:18:49 +000079 return re.sub(r'(?m)^\.', '..',
Guido van Rossumfcfb6321998-08-04 15:29:54 +000080 re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data))
Guido van Rossum69a79bc1998-07-13 15:18:49 +000081
Guido van Rossumbbe323e1998-01-29 17:24:40 +000082class SMTP:
Guido van Rossumfcfb6321998-08-04 15:29:54 +000083 """This class manages a connection to an SMTP or ESMTP server.
84 SMTP Objects:
85 SMTP objects have the following attributes:
86 helo_resp
87 This is the message given by the server in responce to the
88 most recent HELO command.
89
90 ehlo_resp
91 This is the message given by the server in responce to the
92 most recent EHLO command. This is usually multiline.
93
94 does_esmtp
95 This is a True value _after you do an EHLO command_, if the
96 server supports ESMTP.
97
98 esmtp_features
99 This is a dictionary, which, if the server supports ESMTP,
100 will _after you do an EHLO command_, contain the names of the
101 SMTP service extentions this server supports, and their
102 parameters (if any).
103 Note, all extention names are mapped to lower case in the
104 dictionary.
105
106 For method docs, see each method's docstrings. In general, there is
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000107 a method of the same name to perform each SMTP command, and there
108 is a method called 'sendmail' that will do an entire mail
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000109 transaction.
110 """
Guido van Rossum95e6f701998-06-25 02:15:50 +0000111 debuglevel = 0
112 file = None
113 helo_resp = None
114 ehlo_resp = None
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000115 does_esmtp = 0
Guido van Rossum95e6f701998-06-25 02:15:50 +0000116
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000117 def __init__(self, host = '', port = 0):
118 """Initialize a new instance.
119
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000120 If specified, `host' is the name of the remote host to which to
121 connect. If specified, `port' specifies the port to which to connect.
122 By default, smtplib.SMTP_PORT is used.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000123
124 """
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000125 self.esmtp_features = {}
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000126 if host: self.connect(host, port)
127
128 def set_debuglevel(self, debuglevel):
129 """Set the debug output level.
130
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000131 A non-false value results in debug messages for connection and for all
132 messages sent to and received from the server.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000133
134 """
135 self.debuglevel = debuglevel
136
137 def connect(self, host='localhost', port = 0):
138 """Connect to a host on a given port.
Guido van Rossum95e6f701998-06-25 02:15:50 +0000139
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000140 If the hostname ends with a colon (`:') followed by a number, and
141 there is no port specified, that suffix will be stripped off and the
142 number interpreted as the port number to use.
Guido van Rossum95e6f701998-06-25 02:15:50 +0000143
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000144 Note: This method is automatically invoked by __init__, if a host is
145 specified during instantiation.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000146
147 """
148 if not port:
149 i = string.find(host, ':')
150 if i >= 0:
151 host, port = host[:i], host[i+1:]
152 try: port = string.atoi(port)
153 except string.atoi_error:
154 raise socket.error, "nonnumeric port"
155 if not port: port = SMTP_PORT
156 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
157 if self.debuglevel > 0: print 'connect:', (host, port)
158 self.sock.connect(host, port)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000159 (code,msg)=self.getreply()
160 if self.debuglevel >0 : print "connect:", msg
161 return msg
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000162
163 def send(self, str):
164 """Send `str' to the server."""
165 if self.debuglevel > 0: print 'send:', `str`
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000166 if self.sock:
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000167 try:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000168 self.sock.send(str)
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000169 except socket.error:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000170 raise SMTPServerDisconnected
Guido van Rossumfc40a831998-01-29 17:26:45 +0000171 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000172 raise SMTPServerDisconnected
Guido van Rossumfc40a831998-01-29 17:26:45 +0000173
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000174 def putcmd(self, cmd, args=""):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000175 """Send a command to the server."""
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000176 str = '%s %s%s' % (cmd, args, CRLF)
177 self.send(str)
178
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000179 def getreply(self):
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000180 """Get a reply from the server.
181
182 Returns a tuple consisting of:
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000183
184 - server response code (e.g. '250', or such, if all goes well)
185 Note: returns -1 if it can't read response code.
186
187 - server response string corresponding to response code (multiline
188 responses are converted to a single, multiline string).
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000189 """
190 resp=[]
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000191 self.file = self.sock.makefile('rb')
192 while 1:
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000193 line = self.file.readline()
194 if self.debuglevel > 0: print 'reply:', `line`
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000195 resp.append(string.strip(line[4:]))
196 code=line[:3]
197 #check if multiline resp
198 if line[3:4]!="-":
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000199 break
200 try:
201 errcode = string.atoi(code)
202 except(ValueError):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000203 errcode = -1
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000204
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000205 errmsg = string.join(resp,"\n")
206 if self.debuglevel > 0:
Guido van Rossumfc40a831998-01-29 17:26:45 +0000207 print 'reply: retcode (%s); Msg: %s' % (errcode,errmsg)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000208 return errcode, errmsg
209
210 def docmd(self, cmd, args=""):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000211 """Send a command, and return its response code."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000212 self.putcmd(cmd,args)
213 (code,msg)=self.getreply()
214 return code
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000215
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000216 # std smtp commands
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000217 def helo(self, name=''):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000218 """SMTP 'helo' command.
219 Hostname to send for this command defaults to the FQDN of the local
220 host.
221 """
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000222 name=string.strip(name)
223 if len(name)==0:
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000224 name=socket.gethostbyaddr(socket.gethostname())[0]
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000225 self.putcmd("helo",name)
226 (code,msg)=self.getreply()
227 self.helo_resp=msg
228 return code
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000229
Guido van Rossum95e6f701998-06-25 02:15:50 +0000230 def ehlo(self, name=''):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000231 """ SMTP 'ehlo' command.
232 Hostname to send for this command defaults to the FQDN of the local
233 host.
234 """
Guido van Rossum95e6f701998-06-25 02:15:50 +0000235 name=string.strip(name)
236 if len(name)==0:
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000237 name=socket.gethostbyaddr(socket.gethostname())[0]
Guido van Rossum95e6f701998-06-25 02:15:50 +0000238 self.putcmd("ehlo",name)
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000239 (code,msg)=self.getreply()
240 # According to RFC1869 some (badly written)
241 # MTA's will disconnect on an ehlo. Toss an exception if
242 # that happens -ddm
243 if code == -1 and len(msg) == 0:
244 raise SMTPServerDisconnected
Guido van Rossum95e6f701998-06-25 02:15:50 +0000245 self.ehlo_resp=msg
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000246 if code<>250:
247 return code
248 self.does_esmtp=1
249 #parse the ehlo responce -ddm
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000250 resp=string.split(self.ehlo_resp,'\n')
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000251 del resp[0]
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000252 for each in resp:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000253 m=re.match(r'(?P<feature>[A-Za-z0-9][A-Za-z0-9\-]*)',each)
254 if m:
255 feature=string.lower(m.group("feature"))
256 params=string.strip(m.string[m.end("feature"):])
257 self.esmtp_features[feature]=params
Guido van Rossum95e6f701998-06-25 02:15:50 +0000258 return code
259
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000260 def has_extn(self, opt):
261 """Does the server support a given SMTP service extension?"""
262 return self.esmtp_features.has_key(string.lower(opt))
Guido van Rossum95e6f701998-06-25 02:15:50 +0000263
Guido van Rossum18586f41998-04-03 17:03:13 +0000264 def help(self, args=''):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000265 """SMTP 'help' command.
266 Returns help text from server."""
Guido van Rossum18586f41998-04-03 17:03:13 +0000267 self.putcmd("help", args)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000268 (code,msg)=self.getreply()
269 return msg
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000270
271 def rset(self):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000272 """SMTP 'rset' command -- resets session."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000273 code=self.docmd("rset")
274 return code
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000275
276 def noop(self):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000277 """SMTP 'noop' command -- doesn't do anything :>"""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000278 code=self.docmd("noop")
279 return code
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000280
Guido van Rossum95e6f701998-06-25 02:15:50 +0000281 def mail(self,sender,options=[]):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000282 """SMTP 'mail' command -- begins mail xfer session."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000283 optionlist = ''
284 if options and self.does_esmtp:
285 optionlist = string.join(options, ' ')
286 self.putcmd("mail", "FROM:%s %s" % (quoteaddr(sender) ,optionlist))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000287 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000288
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000289 def rcpt(self,recip,options=[]):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000290 """SMTP 'rcpt' command -- indicates 1 recipient for this mail."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000291 optionlist = ''
292 if options and self.does_esmtp:
293 optionlist = string.join(options, ' ')
294 self.putcmd("rcpt","TO:%s %s" % (quoteaddr(recip),optionlist))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000295 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000296
297 def data(self,msg):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000298 """SMTP 'DATA' command -- sends message data to server.
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000299 Automatically quotes lines beginning with a period per rfc821.
300 """
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000301 self.putcmd("data")
302 (code,repl)=self.getreply()
303 if self.debuglevel >0 : print "data:", (code,repl)
304 if code <> 354:
305 return -1
306 else:
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000307 self.send(quotedata(msg))
308 self.send("%s.%s" % (CRLF, CRLF))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000309 (code,msg)=self.getreply()
310 if self.debuglevel >0 : print "data:", (code,msg)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000311 return code
312
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000313 def verify(self, address):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000314 """SMTP 'verify' command -- checks for address validity."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000315 self.putcmd("vrfy", quoteaddr(address))
316 return self.getreply()
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000317 # a.k.a.
318 vrfy=verify
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000319
320 def expn(self, address):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000321 """SMTP 'verify' command -- checks for address validity."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000322 self.putcmd("expn", quoteaddr(address))
323 return self.getreply()
324
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000325 # some useful methods
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +0000326 def sendmail(self, from_addr, to_addrs, msg, mail_options=[],
327 rcpt_options=[]):
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000328 """This command performs an entire mail transaction.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000329
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000330 The arguments are:
331 - from_addr : The address sending this mail.
332 - to_addrs : A list of addresses to send this mail to. A bare
333 string will be treated as a list with 1 address.
334 - msg : The message to send.
335 - mail_options : List of ESMTP options (such as 8bitmime) for the
336 mail command.
337 - rcpt_options : List of ESMTP options (such as DSN commands) for
338 all the rcpt commands.
339
340 If there has been no previous EHLO or HELO command this session, this
341 method tries ESMTP EHLO first. If the server does ESMTP, message size
342 and each of the specified options will be passed to it. If EHLO
343 fails, HELO will be tried and ESMTP options suppressed.
344
345 This method will return normally if the mail is accepted for at least
346 one recipient. Otherwise it will throw an exception (either
347 SMTPSenderRefused, SMTPRecipientsRefused, or SMTPDataError) That is,
348 if this method does not throw an exception, then someone should get
349 your mail. If this method does not throw an exception, it returns a
350 dictionary, with one entry for each recipient that was refused.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000351
Guido van Rossum95e6f701998-06-25 02:15:50 +0000352 Example:
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000353
354 >>> import smtplib
355 >>> s=smtplib.SMTP("localhost")
Guido van Rossumfc40a831998-01-29 17:26:45 +0000356 >>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000357 >>> msg = '''
358 ... From: Me@my.org
359 ... Subject: testin'...
360 ...
361 ... This is a test '''
362 >>> s.sendmail("me@my.org",tolist,msg)
363 { "three@three.org" : ( 550 ,"User unknown" ) }
364 >>> s.quit()
365
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000366 In the above example, the message was accepted for delivery to three
367 of the four addresses, and one was rejected, with the error code
368 550. If all addresses are accepted, then the method will return an
369 empty dictionary.
370
371 """
Guido van Rossum95e6f701998-06-25 02:15:50 +0000372 if not self.helo_resp and not self.ehlo_resp:
373 if self.ehlo() >= 400:
374 self.helo()
Guido van Rossum95e6f701998-06-25 02:15:50 +0000375 esmtp_opts = []
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000376 if self.does_esmtp:
377 # Hmmm? what's this? -ddm
378 # self.esmtp_features['7bit']=""
379 if self.has_extn('size'):
380 esmtp_opts.append("size=" + `len(msg)`)
381 for option in mail_options:
Guido van Rossum95e6f701998-06-25 02:15:50 +0000382 esmtp_opts.append(option)
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000383
Guido van Rossum95e6f701998-06-25 02:15:50 +0000384 (code,resp) = self.mail(from_addr, esmtp_opts)
385 if code <> 250:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000386 self.rset()
387 raise SMTPSenderRefused
388 senderrs={}
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +0000389 if type(to_addrs) == types.StringType:
390 to_addrs = [to_addrs]
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000391 for each in to_addrs:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000392 (code,resp)=self.rcpt(each, rcpt_options)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000393 if (code <> 250) and (code <> 251):
Guido van Rossumfc40a831998-01-29 17:26:45 +0000394 senderrs[each]=(code,resp)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000395 if len(senderrs)==len(to_addrs):
Guido van Rossum95e6f701998-06-25 02:15:50 +0000396 # the server refused all our recipients
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000397 self.rset()
398 raise SMTPRecipientsRefused
399 code=self.data(msg)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000400 if code <>250 :
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000401 self.rset()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000402 raise SMTPDataError
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000403 #if we got here then somebody got our mail
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000404 return senderrs
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000405
406
407 def close(self):
408 """Close the connection to the SMTP server."""
409 if self.file:
410 self.file.close()
411 self.file = None
412 if self.sock:
413 self.sock.close()
414 self.sock = None
415
416
417 def quit(self):
Guido van Rossum95e6f701998-06-25 02:15:50 +0000418 """Terminate the SMTP session."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000419 self.docmd("quit")
420 self.close()
Guido van Rossum95e6f701998-06-25 02:15:50 +0000421
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000422
Guido van Rossum95e6f701998-06-25 02:15:50 +0000423# Test the sendmail method, which tests most of the others.
424# Note: This always sends to localhost.
425if __name__ == '__main__':
426 import sys, rfc822
427
428 def prompt(prompt):
429 sys.stdout.write(prompt + ": ")
430 return string.strip(sys.stdin.readline())
431
432 fromaddr = prompt("From")
433 toaddrs = string.splitfields(prompt("To"), ',')
434 print "Enter message, end with ^D:"
435 msg = ''
436 while 1:
437 line = sys.stdin.readline()
438 if not line:
439 break
440 msg = msg + line
441 print "Message length is " + `len(msg)`
442
443 server = SMTP('localhost')
444 server.set_debuglevel(1)
445 server.sendmail(fromaddr, toaddrs, msg)
446 server.quit()