blob: 264eafb157045d1d79c78c7d81d82d368902ff6b [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 Warsaw07201771998-12-22 20:37:36 +000041Bugs/TODO:
42 - Exceptions should be classes
43
Barry Warsaw4c4bec81998-12-22 03:02:20 +000044'''
Guido van Rossumbbe323e1998-01-29 17:24:40 +000045
46import socket
Barry Warsaw07201771998-12-22 20:37:36 +000047import string
48import re
Guido van Rossumfcfb6321998-08-04 15:29:54 +000049import rfc822
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +000050import types
Guido van Rossumbbe323e1998-01-29 17:24:40 +000051
52SMTP_PORT = 25
53CRLF="\r\n"
54
55# used for exceptions
Guido van Rossumfc40a831998-01-29 17:26:45 +000056SMTPServerDisconnected="Server not connected"
Guido van Rossumbbe323e1998-01-29 17:24:40 +000057SMTPSenderRefused="Sender address refused"
58SMTPRecipientsRefused="All Recipients refused"
Guido van Rossum95e6f701998-06-25 02:15:50 +000059SMTPDataError="Error transmitting message data"
Guido van Rossumbbe323e1998-01-29 17:24:40 +000060
Guido van Rossum69a79bc1998-07-13 15:18:49 +000061def quoteaddr(addr):
62 """Quote a subset of the email addresses defined by RFC 821.
63
Barry Warsawa7d9bdf1998-12-22 03:24:27 +000064 Should be able to handle anything rfc822.parseaddr can handle.
65 """
Guido van Rossumfcfb6321998-08-04 15:29:54 +000066 m=None
Guido van Rossum69a79bc1998-07-13 15:18:49 +000067 try:
Guido van Rossumfcfb6321998-08-04 15:29:54 +000068 m=rfc822.parseaddr(addr)[1]
69 except AttributeError:
70 pass
71 if not m:
72 #something weird here.. punt -ddm
73 return addr
74 else:
75 return "<%s>" % m
Guido van Rossum69a79bc1998-07-13 15:18:49 +000076
77def quotedata(data):
78 """Quote data for email.
79
Guido van Rossumfcfb6321998-08-04 15:29:54 +000080 Double leading '.', and change Unix newline '\n', or Mac '\r' into
Barry Warsawa7d9bdf1998-12-22 03:24:27 +000081 Internet CRLF end-of-line.
82 """
Guido van Rossum69a79bc1998-07-13 15:18:49 +000083 return re.sub(r'(?m)^\.', '..',
Guido van Rossumfcfb6321998-08-04 15:29:54 +000084 re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data))
Guido van Rossum69a79bc1998-07-13 15:18:49 +000085
Guido van Rossumbbe323e1998-01-29 17:24:40 +000086class SMTP:
Guido van Rossumfcfb6321998-08-04 15:29:54 +000087 """This class manages a connection to an SMTP or ESMTP server.
88 SMTP Objects:
89 SMTP objects have the following attributes:
90 helo_resp
91 This is the message given by the server in responce to the
92 most recent HELO command.
93
94 ehlo_resp
95 This is the message given by the server in responce to the
96 most recent EHLO command. This is usually multiline.
97
98 does_esmtp
99 This is a True value _after you do an EHLO command_, if the
100 server supports ESMTP.
101
102 esmtp_features
103 This is a dictionary, which, if the server supports ESMTP,
104 will _after you do an EHLO command_, contain the names of the
105 SMTP service extentions this server supports, and their
106 parameters (if any).
107 Note, all extention names are mapped to lower case in the
108 dictionary.
109
110 For method docs, see each method's docstrings. In general, there is
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000111 a method of the same name to perform each SMTP command, and there
112 is a method called 'sendmail' that will do an entire mail
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000113 transaction.
114 """
Guido van Rossum95e6f701998-06-25 02:15:50 +0000115 debuglevel = 0
116 file = None
117 helo_resp = None
118 ehlo_resp = None
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000119 does_esmtp = 0
Guido van Rossum95e6f701998-06-25 02:15:50 +0000120
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000121 def __init__(self, host = '', port = 0):
122 """Initialize a new instance.
123
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000124 If specified, `host' is the name of the remote host to which to
125 connect. If specified, `port' specifies the port to which to connect.
126 By default, smtplib.SMTP_PORT is used.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000127
128 """
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000129 self.esmtp_features = {}
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000130 if host: self.connect(host, port)
131
132 def set_debuglevel(self, debuglevel):
133 """Set the debug output level.
134
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000135 A non-false value results in debug messages for connection and for all
136 messages sent to and received from the server.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000137
138 """
139 self.debuglevel = debuglevel
140
141 def connect(self, host='localhost', port = 0):
142 """Connect to a host on a given port.
Guido van Rossum95e6f701998-06-25 02:15:50 +0000143
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000144 If the hostname ends with a colon (`:') followed by a number, and
145 there is no port specified, that suffix will be stripped off and the
146 number interpreted as the port number to use.
Guido van Rossum95e6f701998-06-25 02:15:50 +0000147
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000148 Note: This method is automatically invoked by __init__, if a host is
149 specified during instantiation.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000150
151 """
152 if not port:
153 i = string.find(host, ':')
154 if i >= 0:
155 host, port = host[:i], host[i+1:]
156 try: port = string.atoi(port)
157 except string.atoi_error:
158 raise socket.error, "nonnumeric port"
159 if not port: port = SMTP_PORT
160 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
161 if self.debuglevel > 0: print 'connect:', (host, port)
162 self.sock.connect(host, port)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000163 (code,msg)=self.getreply()
164 if self.debuglevel >0 : print "connect:", msg
165 return msg
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000166
167 def send(self, str):
168 """Send `str' to the server."""
169 if self.debuglevel > 0: print 'send:', `str`
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000170 if self.sock:
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000171 try:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000172 self.sock.send(str)
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000173 except socket.error:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000174 raise SMTPServerDisconnected
Guido van Rossumfc40a831998-01-29 17:26:45 +0000175 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000176 raise SMTPServerDisconnected
Guido van Rossumfc40a831998-01-29 17:26:45 +0000177
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000178 def putcmd(self, cmd, args=""):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000179 """Send a command to the server."""
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000180 str = '%s %s%s' % (cmd, args, CRLF)
181 self.send(str)
182
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000183 def getreply(self):
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000184 """Get a reply from the server.
185
186 Returns a tuple consisting of:
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000187
188 - server response code (e.g. '250', or such, if all goes well)
189 Note: returns -1 if it can't read response code.
190
191 - server response string corresponding to response code (multiline
192 responses are converted to a single, multiline string).
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000193 """
194 resp=[]
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000195 self.file = self.sock.makefile('rb')
196 while 1:
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000197 line = self.file.readline()
198 if self.debuglevel > 0: print 'reply:', `line`
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000199 resp.append(string.strip(line[4:]))
200 code=line[:3]
201 #check if multiline resp
202 if line[3:4]!="-":
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000203 break
204 try:
205 errcode = string.atoi(code)
206 except(ValueError):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000207 errcode = -1
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000208
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000209 errmsg = string.join(resp,"\n")
210 if self.debuglevel > 0:
Guido van Rossumfc40a831998-01-29 17:26:45 +0000211 print 'reply: retcode (%s); Msg: %s' % (errcode,errmsg)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000212 return errcode, errmsg
213
214 def docmd(self, cmd, args=""):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000215 """Send a command, and return its response code."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000216 self.putcmd(cmd,args)
217 (code,msg)=self.getreply()
218 return code
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000219
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000220 # std smtp commands
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000221 def helo(self, name=''):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000222 """SMTP 'helo' command.
223 Hostname to send for this command defaults to the FQDN of the local
224 host.
225 """
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000226 name=string.strip(name)
227 if len(name)==0:
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000228 name=socket.gethostbyaddr(socket.gethostname())[0]
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000229 self.putcmd("helo",name)
230 (code,msg)=self.getreply()
231 self.helo_resp=msg
232 return code
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000233
Guido van Rossum95e6f701998-06-25 02:15:50 +0000234 def ehlo(self, name=''):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000235 """ SMTP 'ehlo' command.
236 Hostname to send for this command defaults to the FQDN of the local
237 host.
238 """
Guido van Rossum95e6f701998-06-25 02:15:50 +0000239 name=string.strip(name)
240 if len(name)==0:
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000241 name=socket.gethostbyaddr(socket.gethostname())[0]
Guido van Rossum95e6f701998-06-25 02:15:50 +0000242 self.putcmd("ehlo",name)
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000243 (code,msg)=self.getreply()
244 # According to RFC1869 some (badly written)
245 # MTA's will disconnect on an ehlo. Toss an exception if
246 # that happens -ddm
247 if code == -1 and len(msg) == 0:
248 raise SMTPServerDisconnected
Guido van Rossum95e6f701998-06-25 02:15:50 +0000249 self.ehlo_resp=msg
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000250 if code<>250:
251 return code
252 self.does_esmtp=1
253 #parse the ehlo responce -ddm
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000254 resp=string.split(self.ehlo_resp,'\n')
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000255 del resp[0]
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000256 for each in resp:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000257 m=re.match(r'(?P<feature>[A-Za-z0-9][A-Za-z0-9\-]*)',each)
258 if m:
259 feature=string.lower(m.group("feature"))
260 params=string.strip(m.string[m.end("feature"):])
261 self.esmtp_features[feature]=params
Guido van Rossum95e6f701998-06-25 02:15:50 +0000262 return code
263
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000264 def has_extn(self, opt):
265 """Does the server support a given SMTP service extension?"""
266 return self.esmtp_features.has_key(string.lower(opt))
Guido van Rossum95e6f701998-06-25 02:15:50 +0000267
Guido van Rossum18586f41998-04-03 17:03:13 +0000268 def help(self, args=''):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000269 """SMTP 'help' command.
270 Returns help text from server."""
Guido van Rossum18586f41998-04-03 17:03:13 +0000271 self.putcmd("help", args)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000272 (code,msg)=self.getreply()
273 return msg
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000274
275 def rset(self):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000276 """SMTP 'rset' command -- resets session."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000277 code=self.docmd("rset")
278 return code
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000279
280 def noop(self):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000281 """SMTP 'noop' command -- doesn't do anything :>"""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000282 code=self.docmd("noop")
283 return code
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000284
Guido van Rossum95e6f701998-06-25 02:15:50 +0000285 def mail(self,sender,options=[]):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000286 """SMTP 'mail' command -- begins mail xfer session."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000287 optionlist = ''
288 if options and self.does_esmtp:
289 optionlist = string.join(options, ' ')
290 self.putcmd("mail", "FROM:%s %s" % (quoteaddr(sender) ,optionlist))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000291 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000292
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000293 def rcpt(self,recip,options=[]):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000294 """SMTP 'rcpt' command -- indicates 1 recipient for this mail."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000295 optionlist = ''
296 if options and self.does_esmtp:
297 optionlist = string.join(options, ' ')
298 self.putcmd("rcpt","TO:%s %s" % (quoteaddr(recip),optionlist))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000299 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000300
301 def data(self,msg):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000302 """SMTP 'DATA' command -- sends message data to server.
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000303 Automatically quotes lines beginning with a period per rfc821.
304 """
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000305 self.putcmd("data")
306 (code,repl)=self.getreply()
307 if self.debuglevel >0 : print "data:", (code,repl)
308 if code <> 354:
309 return -1
310 else:
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000311 self.send(quotedata(msg))
312 self.send("%s.%s" % (CRLF, CRLF))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000313 (code,msg)=self.getreply()
314 if self.debuglevel >0 : print "data:", (code,msg)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000315 return code
316
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000317 def verify(self, address):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000318 """SMTP 'verify' command -- checks for address validity."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000319 self.putcmd("vrfy", quoteaddr(address))
320 return self.getreply()
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000321 # a.k.a.
322 vrfy=verify
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000323
324 def expn(self, address):
Barry Warsawa7d9bdf1998-12-22 03:24:27 +0000325 """SMTP 'verify' command -- checks for address validity."""
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000326 self.putcmd("expn", quoteaddr(address))
327 return self.getreply()
328
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000329 # some useful methods
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +0000330 def sendmail(self, from_addr, to_addrs, msg, mail_options=[],
331 rcpt_options=[]):
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000332 """This command performs an entire mail transaction.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000333
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000334 The arguments are:
335 - from_addr : The address sending this mail.
336 - to_addrs : A list of addresses to send this mail to. A bare
337 string will be treated as a list with 1 address.
338 - msg : The message to send.
339 - mail_options : List of ESMTP options (such as 8bitmime) for the
340 mail command.
341 - rcpt_options : List of ESMTP options (such as DSN commands) for
342 all the rcpt commands.
343
344 If there has been no previous EHLO or HELO command this session, this
345 method tries ESMTP EHLO first. If the server does ESMTP, message size
346 and each of the specified options will be passed to it. If EHLO
347 fails, HELO will be tried and ESMTP options suppressed.
348
349 This method will return normally if the mail is accepted for at least
350 one recipient. Otherwise it will throw an exception (either
351 SMTPSenderRefused, SMTPRecipientsRefused, or SMTPDataError) That is,
352 if this method does not throw an exception, then someone should get
353 your mail. If this method does not throw an exception, it returns a
354 dictionary, with one entry for each recipient that was refused.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000355
Guido van Rossum95e6f701998-06-25 02:15:50 +0000356 Example:
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000357
358 >>> import smtplib
359 >>> s=smtplib.SMTP("localhost")
Guido van Rossumfc40a831998-01-29 17:26:45 +0000360 >>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000361 >>> msg = '''
362 ... From: Me@my.org
363 ... Subject: testin'...
364 ...
365 ... This is a test '''
366 >>> s.sendmail("me@my.org",tolist,msg)
367 { "three@three.org" : ( 550 ,"User unknown" ) }
368 >>> s.quit()
369
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000370 In the above example, the message was accepted for delivery to three
371 of the four addresses, and one was rejected, with the error code
372 550. If all addresses are accepted, then the method will return an
373 empty dictionary.
374
375 """
Guido van Rossum95e6f701998-06-25 02:15:50 +0000376 if not self.helo_resp and not self.ehlo_resp:
377 if self.ehlo() >= 400:
378 self.helo()
Guido van Rossum95e6f701998-06-25 02:15:50 +0000379 esmtp_opts = []
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000380 if self.does_esmtp:
381 # Hmmm? what's this? -ddm
382 # self.esmtp_features['7bit']=""
383 if self.has_extn('size'):
384 esmtp_opts.append("size=" + `len(msg)`)
385 for option in mail_options:
Guido van Rossum95e6f701998-06-25 02:15:50 +0000386 esmtp_opts.append(option)
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000387
Guido van Rossum95e6f701998-06-25 02:15:50 +0000388 (code,resp) = self.mail(from_addr, esmtp_opts)
389 if code <> 250:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000390 self.rset()
391 raise SMTPSenderRefused
392 senderrs={}
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +0000393 if type(to_addrs) == types.StringType:
394 to_addrs = [to_addrs]
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000395 for each in to_addrs:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000396 (code,resp)=self.rcpt(each, rcpt_options)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000397 if (code <> 250) and (code <> 251):
Guido van Rossumfc40a831998-01-29 17:26:45 +0000398 senderrs[each]=(code,resp)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000399 if len(senderrs)==len(to_addrs):
Guido van Rossum95e6f701998-06-25 02:15:50 +0000400 # the server refused all our recipients
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000401 self.rset()
402 raise SMTPRecipientsRefused
403 code=self.data(msg)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000404 if code <>250 :
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000405 self.rset()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000406 raise SMTPDataError
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000407 #if we got here then somebody got our mail
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000408 return senderrs
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000409
410
411 def close(self):
412 """Close the connection to the SMTP server."""
413 if self.file:
414 self.file.close()
415 self.file = None
416 if self.sock:
417 self.sock.close()
418 self.sock = None
419
420
421 def quit(self):
Guido van Rossum95e6f701998-06-25 02:15:50 +0000422 """Terminate the SMTP session."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000423 self.docmd("quit")
424 self.close()
Guido van Rossum95e6f701998-06-25 02:15:50 +0000425
Barry Warsaw4c4bec81998-12-22 03:02:20 +0000426
Guido van Rossum95e6f701998-06-25 02:15:50 +0000427# Test the sendmail method, which tests most of the others.
428# Note: This always sends to localhost.
429if __name__ == '__main__':
430 import sys, rfc822
431
432 def prompt(prompt):
433 sys.stdout.write(prompt + ": ")
434 return string.strip(sys.stdin.readline())
435
436 fromaddr = prompt("From")
437 toaddrs = string.splitfields(prompt("To"), ',')
438 print "Enter message, end with ^D:"
439 msg = ''
440 while 1:
441 line = sys.stdin.readline()
442 if not line:
443 break
444 msg = msg + line
445 print "Message length is " + `len(msg)`
446
447 server = SMTP('localhost')
448 server.set_debuglevel(1)
449 server.sendmail(fromaddr, toaddrs, msg)
450 server.quit()