diff options
author | Guido van Rossum <guido@python.org> | 1998-07-13 15:18:49 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1998-07-13 15:18:49 (GMT) |
commit | 69a79bca6860ae84f502f163176bf49b633d6add (patch) | |
tree | 3db94c94a01578a2eb3753381fedb0084ade463b /Lib | |
parent | 5c44027d8ab77fb40ec9a386596e59251c1b7146 (diff) | |
download | cpython-69a79bca6860ae84f502f163176bf49b633d6add.zip cpython-69a79bca6860ae84f502f163176bf49b633d6add.tar.gz cpython-69a79bca6860ae84f502f163176bf49b633d6add.tar.bz2 |
Better RFC 821 compliance (MAIL and RCPT, and CRLF in data)
by Carey Evans <c.evans@clear.net.nz>, for picky mail servers.
Diffstat (limited to 'Lib')
-rwxr-xr-x | Lib/smtplib.py | 52 |
1 files changed, 37 insertions, 15 deletions
diff --git a/Lib/smtplib.py b/Lib/smtplib.py index 95c0f96..2ffc248 100755 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -4,6 +4,8 @@ Author: The Dragon De Monsyne <dragondm@integral.org> ESMTP support, test code and doc fixes added by Eric S. Raymond <esr@thyrsus.com> +Better RFC 821 compliance (MAIL and RCPT, and CRLF in data) +by Carey Evans <c.evans@clear.net.nz>, for picky mail servers. (This was modified from the Python 1.5 library HTTP lib.) @@ -43,6 +45,37 @@ SMTPSenderRefused="Sender address refused" SMTPRecipientsRefused="All Recipients refused" SMTPDataError="Error transmitting message data" +def quoteaddr(addr): + """Quote a subset of the email addresses defined by RFC 821. + + Technically, only a <mailbox> is allowed. In addition, + email addresses without a domain are permitted. + + Addresses will not be modified if they are already quoted + (actually if they begin with '<' and end with '>'.""" + if re.match('(?s)\A<.*>\Z', addr): + return addr + + localpart = None + domain = '' + try: + at = string.rindex(addr, '@') + localpart = addr[:at] + domain = addr[at:] + except ValueError: + localpart = addr + + pat = re.compile(r'([<>()\[\]\\,;:@\"\001-\037\177])') + return '<%s%s>' % (pat.sub(r'\\\1', localpart), domain) + +def quotedata(data): + """Quote data for email. + + Double leading '.', and change Unix newline '\n' into + Internet CRLF end-of-line.""" + return re.sub(r'(?m)^\.', '..', + re.sub(r'\r?\n', CRLF, data)) + class SMTP: """This class manages a connection to an SMTP or ESMTP server.""" debuglevel = 0 @@ -208,36 +241,25 @@ class SMTP: options = " " + string.joinfields(options, ' ') else: options = '' - self.putcmd("mail from:", sender + options) + self.putcmd("mail", "from:" + quoteaddr(sender) + options) return self.getreply() def rcpt(self,recip): """ SMTP 'rcpt' command. Indicates 1 recipient for this mail. """ - self.putcmd("rcpt","to: %s" % recip) + self.putcmd("rcpt","to:%s" % quoteaddr(recip)) return self.getreply() def data(self,msg): """ SMTP 'DATA' command. Sends message data to server. Automatically quotes lines beginning with a period per rfc821. """ - #quote periods in msg according to RFC821 - # ps, I don't know why I have to do it this way... doing: - # quotepat=re.compile(r"^[.]",re.M) - # msg=re.sub(quotepat,"..",msg) - # should work, but it dosen't (it doubles the number of any - # contiguous series of .'s at the beginning of a line, - #instead of just adding one. ) - quotepat=re.compile(r"^[.]+",re.M) - def m(pat): - return "."+pat.group(0) - msg=re.sub(quotepat,m,msg) self.putcmd("data") (code,repl)=self.getreply() if self.debuglevel >0 : print "data:", (code,repl) if code <> 354: return -1 else: - self.send(msg) - self.send("\n.\n") + self.send(quotedata(msg)) + self.send("%s.%s" % (CRLF, CRLF)) (code,msg)=self.getreply() if self.debuglevel >0 : print "data:", (code,msg) return code |