Skip to content

Commit

Permalink
Better RFC 821 compliance (MAIL and RCPT, and CRLF in data)
Browse files Browse the repository at this point in the history
by Carey Evans <[email protected]>, for picky mail servers.
  • Loading branch information
gvanrossum committed Jul 13, 1998
1 parent 5c44027 commit 69a79bc
Showing 1 changed file with 37 additions and 15 deletions.
52 changes: 37 additions & 15 deletions Lib/smtplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
Author: The Dragon De Monsyne <[email protected]>
ESMTP support, test code and doc fixes added by
Eric S. Raymond <[email protected]>
Better RFC 821 compliance (MAIL and RCPT, and CRLF in data)
by Carey Evans <[email protected]>, for picky mail servers.
(This was modified from the Python 1.5 library HTTP lib.)
Expand Down Expand Up @@ -43,6 +45,37 @@
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
Expand Down Expand Up @@ -208,36 +241,25 @@ def mail(self,sender,options=[]):
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
Expand Down

0 comments on commit 69a79bc

Please sign in to comment.