blob: 07f53fa195a6ec54bc4e9c64e58955d4748df65b [file] [log] [blame]
Guido van Rossum95e6f701998-06-25 02:15:50 +00001#!/usr/bin/python
2"""SMTP/ESMTP client class.
Guido van Rossumbbe323e1998-01-29 17:24:40 +00003
4Author: The Dragon De Monsyne <dragondm@integral.org>
Guido van Rossum95e6f701998-06-25 02:15:50 +00005ESMTP support, test code and doc fixes added by
Guido van Rossumfcfb6321998-08-04 15:29:54 +00006 Eric S. Raymond <esr@thyrsus.com>
Guido van Rossum69a79bc1998-07-13 15:18:49 +00007Better RFC 821 compliance (MAIL and RCPT, and CRLF in data)
Guido van Rossumfcfb6321998-08-04 15:29:54 +00008 by Carey Evans <c.evans@clear.net.nz>, for picky mail servers.
9
Guido van Rossumbbe323e1998-01-29 17:24:40 +000010(This was modified from the Python 1.5 library HTTP lib.)
11
Guido van Rossum95e6f701998-06-25 02:15:50 +000012This should follow RFC 821 (SMTP) and RFC 1869 (ESMTP).
Guido van Rossumbbe323e1998-01-29 17:24:40 +000013
Guido van Rossumfcfb6321998-08-04 15:29:54 +000014Notes:
15
16Please remember, when doing ESMTP, that the names of the SMTP service
17extensions are NOT the same thing as the option keyords for the RCPT
18and MAIL commands!
19
Guido van Rossumbbe323e1998-01-29 17:24:40 +000020Example:
21
22>>> import smtplib
23>>> s=smtplib.SMTP("localhost")
24>>> print s.help()
25This is Sendmail version 8.8.4
26Topics:
27 HELO EHLO MAIL RCPT DATA
28 RSET NOOP QUIT HELP VRFY
29 EXPN VERB ETRN DSN
30For more info use "HELP <topic>".
31To report bugs in the implementation send email to
32 sendmail-bugs@sendmail.org.
33For local information send email to Postmaster at your site.
34End of HELP info
35>>> s.putcmd("vrfy","someone@here")
36>>> s.getreply()
37(250, "Somebody OverHere <somebody@here.my.org>")
38>>> s.quit()
39
40"""
41
42import socket
Guido van Rossumfcfb6321998-08-04 15:29:54 +000043import string, re
44import 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
50# used for exceptions
Guido van Rossumfc40a831998-01-29 17:26:45 +000051SMTPServerDisconnected="Server not connected"
Guido van Rossumbbe323e1998-01-29 17:24:40 +000052SMTPSenderRefused="Sender address refused"
53SMTPRecipientsRefused="All Recipients refused"
Guido van Rossum95e6f701998-06-25 02:15:50 +000054SMTPDataError="Error transmitting message data"
Guido van Rossumbbe323e1998-01-29 17:24:40 +000055
Guido van Rossum69a79bc1998-07-13 15:18:49 +000056def quoteaddr(addr):
57 """Quote a subset of the email addresses defined by RFC 821.
58
Guido van Rossumfcfb6321998-08-04 15:29:54 +000059 Should be able to handle anything rfc822.parseaddr can handle."""
Guido van Rossum69a79bc1998-07-13 15:18:49 +000060
Guido van Rossumfcfb6321998-08-04 15:29:54 +000061 m=None
Guido van Rossum69a79bc1998-07-13 15:18:49 +000062 try:
Guido van Rossumfcfb6321998-08-04 15:29:54 +000063 m=rfc822.parseaddr(addr)[1]
64 except AttributeError:
65 pass
66 if not m:
67 #something weird here.. punt -ddm
68 return addr
69 else:
70 return "<%s>" % m
Guido van Rossum69a79bc1998-07-13 15:18:49 +000071
72def quotedata(data):
73 """Quote data for email.
74
Guido van Rossumfcfb6321998-08-04 15:29:54 +000075 Double leading '.', and change Unix newline '\n', or Mac '\r' into
Guido van Rossum69a79bc1998-07-13 15:18:49 +000076 Internet CRLF end-of-line."""
77 return re.sub(r'(?m)^\.', '..',
Guido van Rossumfcfb6321998-08-04 15:29:54 +000078 re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data))
Guido van Rossum69a79bc1998-07-13 15:18:49 +000079
Guido van Rossumbbe323e1998-01-29 17:24:40 +000080class SMTP:
Guido van Rossumfcfb6321998-08-04 15:29:54 +000081 """This class manages a connection to an SMTP or ESMTP server.
82 SMTP Objects:
83 SMTP objects have the following attributes:
84 helo_resp
85 This is the message given by the server in responce to the
86 most recent HELO command.
87
88 ehlo_resp
89 This is the message given by the server in responce to the
90 most recent EHLO command. This is usually multiline.
91
92 does_esmtp
93 This is a True value _after you do an EHLO command_, if the
94 server supports ESMTP.
95
96 esmtp_features
97 This is a dictionary, which, if the server supports ESMTP,
98 will _after you do an EHLO command_, contain the names of the
99 SMTP service extentions this server supports, and their
100 parameters (if any).
101 Note, all extention names are mapped to lower case in the
102 dictionary.
103
104 For method docs, see each method's docstrings. In general, there is
105 a method of the same name to preform each SMTP comand, and there
106 is a method called 'sendmail' that will do an entiere mail
107 transaction."""
108
Guido van Rossum95e6f701998-06-25 02:15:50 +0000109 debuglevel = 0
110 file = None
111 helo_resp = None
112 ehlo_resp = None
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000113 does_esmtp = 0
Guido van Rossum95e6f701998-06-25 02:15:50 +0000114
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000115 def __init__(self, host = '', port = 0):
116 """Initialize a new instance.
117
118 If specified, `host' is the name of the remote host to which
119 to connect. If specified, `port' specifies the port to which
120 to connect. By default, smtplib.SMTP_PORT is used.
121
122 """
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000123 self.esmtp_features = {}
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000124 if host: self.connect(host, port)
125
126 def set_debuglevel(self, debuglevel):
127 """Set the debug output level.
128
129 A non-false value results in debug messages for connection and
130 for all messages sent to and received from the server.
131
132 """
133 self.debuglevel = debuglevel
134
135 def connect(self, host='localhost', port = 0):
136 """Connect to a host on a given port.
Guido van Rossum95e6f701998-06-25 02:15:50 +0000137
138 If the hostname ends with a colon (`:') followed by a number,
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000139 and there is no port specified, that suffix will be stripped
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000140 off and the number interpreted as the port number to use.
Guido van Rossum95e6f701998-06-25 02:15:50 +0000141
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000142 Note: This method is automatically invoked by __init__,
143 if a host is specified during instantiation.
144
145 """
146 if not port:
147 i = string.find(host, ':')
148 if i >= 0:
149 host, port = host[:i], host[i+1:]
150 try: port = string.atoi(port)
151 except string.atoi_error:
152 raise socket.error, "nonnumeric port"
153 if not port: port = SMTP_PORT
154 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
155 if self.debuglevel > 0: print 'connect:', (host, port)
156 self.sock.connect(host, port)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000157 (code,msg)=self.getreply()
158 if self.debuglevel >0 : print "connect:", msg
159 return msg
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000160
161 def send(self, str):
162 """Send `str' to the server."""
163 if self.debuglevel > 0: print 'send:', `str`
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000164 if self.sock:
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000165 try:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000166 self.sock.send(str)
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000167 except socket.error:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000168 raise SMTPServerDisconnected
Guido van Rossumfc40a831998-01-29 17:26:45 +0000169 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000170 raise SMTPServerDisconnected
Guido van Rossumfc40a831998-01-29 17:26:45 +0000171
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000172 def putcmd(self, cmd, args=""):
173 """Send a command to the server.
174 """
175 str = '%s %s%s' % (cmd, args, CRLF)
176 self.send(str)
177
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000178 def getreply(self):
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000179 """Get a reply from the server.
180
181 Returns a tuple consisting of:
182 - server response code (e.g. '250', or such, if all goes well)
Guido van Rossum95e6f701998-06-25 02:15:50 +0000183 Note: returns -1 if it can't read response code.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000184 - server response string corresponding to response code
Guido van Rossum95e6f701998-06-25 02:15:50 +0000185 (note : multiline responses converted to a single,
Guido van Rossumfc40a831998-01-29 17:26:45 +0000186 multiline string)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000187 """
188 resp=[]
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000189 self.file = self.sock.makefile('rb')
190 while 1:
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000191 line = self.file.readline()
192 if self.debuglevel > 0: print 'reply:', `line`
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000193 resp.append(string.strip(line[4:]))
194 code=line[:3]
195 #check if multiline resp
196 if line[3:4]!="-":
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000197 break
198 try:
199 errcode = string.atoi(code)
200 except(ValueError):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000201 errcode = -1
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000202
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000203 errmsg = string.join(resp,"\n")
204 if self.debuglevel > 0:
Guido van Rossumfc40a831998-01-29 17:26:45 +0000205 print 'reply: retcode (%s); Msg: %s' % (errcode,errmsg)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000206 return errcode, errmsg
207
208 def docmd(self, cmd, args=""):
Guido van Rossum95e6f701998-06-25 02:15:50 +0000209 """ Send a command, and return its response code """
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000210
211 self.putcmd(cmd,args)
212 (code,msg)=self.getreply()
213 return code
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000214# std smtp commands
215
216 def helo(self, name=''):
217 """ SMTP 'helo' command. Hostname to send for this command
218 defaults to the FQDN of the local host """
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000219 name=string.strip(name)
220 if len(name)==0:
221 name=socket.gethostbyaddr(socket.gethostname())[0]
222 self.putcmd("helo",name)
223 (code,msg)=self.getreply()
224 self.helo_resp=msg
225 return code
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000226
Guido van Rossum95e6f701998-06-25 02:15:50 +0000227 def ehlo(self, name=''):
228 """ SMTP 'ehlo' command. Hostname to send for this command
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000229 defaults to the FQDN of the local host. """
Guido van Rossum95e6f701998-06-25 02:15:50 +0000230 name=string.strip(name)
231 if len(name)==0:
232 name=socket.gethostbyaddr(socket.gethostname())[0]
233 self.putcmd("ehlo",name)
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000234 (code,msg)=self.getreply()
235 # According to RFC1869 some (badly written)
236 # MTA's will disconnect on an ehlo. Toss an exception if
237 # that happens -ddm
238 if code == -1 and len(msg) == 0:
239 raise SMTPServerDisconnected
Guido van Rossum95e6f701998-06-25 02:15:50 +0000240 self.ehlo_resp=msg
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000241 if code<>250:
242 return code
243 self.does_esmtp=1
244 #parse the ehlo responce -ddm
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000245 resp=string.split(self.ehlo_resp,'\n')
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000246 del resp[0]
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000247 for each in resp:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000248 m=re.match(r'(?P<feature>[A-Za-z0-9][A-Za-z0-9\-]*)',each)
249 if m:
250 feature=string.lower(m.group("feature"))
251 params=string.strip(m.string[m.end("feature"):])
252 self.esmtp_features[feature]=params
Guido van Rossum95e6f701998-06-25 02:15:50 +0000253 return code
254
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000255 def has_extn(self, opt):
256 """Does the server support a given SMTP service extension?"""
257 return self.esmtp_features.has_key(string.lower(opt))
Guido van Rossum95e6f701998-06-25 02:15:50 +0000258
Guido van Rossum18586f41998-04-03 17:03:13 +0000259 def help(self, args=''):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000260 """ SMTP 'help' command. Returns help text from server """
Guido van Rossum18586f41998-04-03 17:03:13 +0000261 self.putcmd("help", args)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000262 (code,msg)=self.getreply()
263 return msg
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000264
265 def rset(self):
266 """ SMTP 'rset' command. Resets session. """
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000267 code=self.docmd("rset")
268 return code
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000269
270 def noop(self):
Guido van Rossum95e6f701998-06-25 02:15:50 +0000271 """ SMTP 'noop' command. Doesn't do anything :> """
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000272 code=self.docmd("noop")
273 return code
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000274
Guido van Rossum95e6f701998-06-25 02:15:50 +0000275 def mail(self,sender,options=[]):
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000276 """ SMTP 'mail' command. Begins mail xfer session. """
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000277 optionlist = ''
278 if options and self.does_esmtp:
279 optionlist = string.join(options, ' ')
280 self.putcmd("mail", "FROM:%s %s" % (quoteaddr(sender) ,optionlist))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000281 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000282
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000283 def rcpt(self,recip,options=[]):
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000284 """ SMTP 'rcpt' command. Indicates 1 recipient for this mail. """
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000285 optionlist = ''
286 if options and self.does_esmtp:
287 optionlist = string.join(options, ' ')
288 self.putcmd("rcpt","TO:%s %s" % (quoteaddr(recip),optionlist))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000289 return self.getreply()
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000290
291 def data(self,msg):
292 """ SMTP 'DATA' command. Sends message data to server.
Guido van Rossum95e6f701998-06-25 02:15:50 +0000293 Automatically quotes lines beginning with a period per rfc821. """
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000294 self.putcmd("data")
295 (code,repl)=self.getreply()
296 if self.debuglevel >0 : print "data:", (code,repl)
297 if code <> 354:
298 return -1
299 else:
Guido van Rossum69a79bc1998-07-13 15:18:49 +0000300 self.send(quotedata(msg))
301 self.send("%s.%s" % (CRLF, CRLF))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000302 (code,msg)=self.getreply()
303 if self.debuglevel >0 : print "data:", (code,msg)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000304 return code
305
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000306 def vrfy(self, address):
307 return self.verify(address)
308
309 def verify(self, address):
310 """ SMTP 'verify' command. Checks for address validity. """
311 self.putcmd("vrfy", quoteaddr(address))
312 return self.getreply()
313
314 def expn(self, address):
315 """ SMTP 'verify' command. Checks for address validity. """
316 self.putcmd("expn", quoteaddr(address))
317 return self.getreply()
318
319
Guido van Rossum95e6f701998-06-25 02:15:50 +0000320#some useful methods
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +0000321 def sendmail(self, from_addr, to_addrs, msg, mail_options=[],
322 rcpt_options=[]):
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000323 """ This command performs an entire mail transaction.
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000324 The arguments are:
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000325 - from_addr : The address sending this mail.
326 - to_addrs : a list of addresses to send this mail to
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +0000327 (a string will be treated as a list with 1 address)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000328 - msg : the message to send.
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000329 - mail_options : list of ESMTP options (such as 8bitmime)
330 for the mail command
331 - rcpt_options : List of ESMTP options (such as DSN commands)
332 for all the rcpt commands
Guido van Rossum2880f6e1998-08-10 20:07:00 +0000333 If there has been no previous EHLO or HELO command this session,
334 this method tries ESMTP EHLO first. If the server does ESMTP, message
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000335 size and each of the specified options will be passed to it.
336 If EHLO fails, HELO will be tried and ESMTP options suppressed.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000337
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000338 This method will return normally if the mail is accepted for at least
Guido van Rossum95e6f701998-06-25 02:15:50 +0000339 one recipient. Otherwise it will throw an exception (either
340 SMTPSenderRefused, SMTPRecipientsRefused, or SMTPDataError)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000341 That is, if this method does not throw an exception, then someone
Guido van Rossum95e6f701998-06-25 02:15:50 +0000342 should get your mail. If this method does not throw an exception,
343 it returns a dictionary, with one entry for each recipient that was
Guido van Rossumfc40a831998-01-29 17:26:45 +0000344 refused.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000345
Guido van Rossum95e6f701998-06-25 02:15:50 +0000346 Example:
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000347
348 >>> import smtplib
349 >>> s=smtplib.SMTP("localhost")
Guido van Rossumfc40a831998-01-29 17:26:45 +0000350 >>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000351 >>> msg = '''
352 ... From: Me@my.org
353 ... Subject: testin'...
354 ...
355 ... This is a test '''
356 >>> s.sendmail("me@my.org",tolist,msg)
357 { "three@three.org" : ( 550 ,"User unknown" ) }
358 >>> s.quit()
359
Guido van Rossumfc40a831998-01-29 17:26:45 +0000360 In the above example, the message was accepted for delivery to
361 three of the four addresses, and one was rejected, with the error
362 code 550. If all addresses are accepted, then the method
363 will return an empty dictionary.
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000364 """
Guido van Rossum95e6f701998-06-25 02:15:50 +0000365 if not self.helo_resp and not self.ehlo_resp:
366 if self.ehlo() >= 400:
367 self.helo()
Guido van Rossum95e6f701998-06-25 02:15:50 +0000368 esmtp_opts = []
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000369 if self.does_esmtp:
370 # Hmmm? what's this? -ddm
371 # self.esmtp_features['7bit']=""
372 if self.has_extn('size'):
373 esmtp_opts.append("size=" + `len(msg)`)
374 for option in mail_options:
Guido van Rossum95e6f701998-06-25 02:15:50 +0000375 esmtp_opts.append(option)
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000376
Guido van Rossum95e6f701998-06-25 02:15:50 +0000377 (code,resp) = self.mail(from_addr, esmtp_opts)
378 if code <> 250:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000379 self.rset()
380 raise SMTPSenderRefused
381 senderrs={}
Jeremy Hylton31bb8ce1998-08-13 19:57:46 +0000382 if type(to_addrs) == types.StringType:
383 to_addrs = [to_addrs]
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000384 for each in to_addrs:
Guido van Rossumfcfb6321998-08-04 15:29:54 +0000385 (code,resp)=self.rcpt(each, rcpt_options)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000386 if (code <> 250) and (code <> 251):
Guido van Rossumfc40a831998-01-29 17:26:45 +0000387 senderrs[each]=(code,resp)
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000388 if len(senderrs)==len(to_addrs):
Guido van Rossum95e6f701998-06-25 02:15:50 +0000389 # the server refused all our recipients
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000390 self.rset()
391 raise SMTPRecipientsRefused
392 code=self.data(msg)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000393 if code <>250 :
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000394 self.rset()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000395 raise SMTPDataError
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000396 #if we got here then somebody got our mail
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000397 return senderrs
Guido van Rossumbbe323e1998-01-29 17:24:40 +0000398
399
400 def close(self):
401 """Close the connection to the SMTP server."""
402 if self.file:
403 self.file.close()
404 self.file = None
405 if self.sock:
406 self.sock.close()
407 self.sock = None
408
409
410 def quit(self):
Guido van Rossum95e6f701998-06-25 02:15:50 +0000411 """Terminate the SMTP session."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000412 self.docmd("quit")
413 self.close()
Guido van Rossum95e6f701998-06-25 02:15:50 +0000414
415# Test the sendmail method, which tests most of the others.
416# Note: This always sends to localhost.
417if __name__ == '__main__':
418 import sys, rfc822
419
420 def prompt(prompt):
421 sys.stdout.write(prompt + ": ")
422 return string.strip(sys.stdin.readline())
423
424 fromaddr = prompt("From")
425 toaddrs = string.splitfields(prompt("To"), ',')
426 print "Enter message, end with ^D:"
427 msg = ''
428 while 1:
429 line = sys.stdin.readline()
430 if not line:
431 break
432 msg = msg + line
433 print "Message length is " + `len(msg)`
434
435 server = SMTP('localhost')
436 server.set_debuglevel(1)
437 server.sendmail(fromaddr, toaddrs, msg)
438 server.quit()