10a8c90248264a8b26970b4473770bcc3df8515fJosh Gao#! /usr/bin/env python
20a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
30a8c90248264a8b26970b4473770bcc3df8515fJosh Gao'''SMTP/ESMTP client class.
40a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
50a8c90248264a8b26970b4473770bcc3df8515fJosh GaoThis should follow RFC 821 (SMTP), RFC 1869 (ESMTP), RFC 2554 (SMTP
60a8c90248264a8b26970b4473770bcc3df8515fJosh GaoAuthentication) and RFC 2487 (Secure SMTP over TLS).
70a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
80a8c90248264a8b26970b4473770bcc3df8515fJosh GaoNotes:
90a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
100a8c90248264a8b26970b4473770bcc3df8515fJosh GaoPlease remember, when doing ESMTP, that the names of the SMTP service
110a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoextensions are NOT the same thing as the option keywords for the RCPT
120a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoand MAIL commands!
130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
140a8c90248264a8b26970b4473770bcc3df8515fJosh GaoExample:
150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao  >>> import smtplib
170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao  >>> s=smtplib.SMTP("localhost")
180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao  >>> print s.help()
190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao  This is Sendmail version 8.8.4
200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao  Topics:
210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao      HELO    EHLO    MAIL    RCPT    DATA
220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao      RSET    NOOP    QUIT    HELP    VRFY
230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao      EXPN    VERB    ETRN    DSN
240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao  For more info use "HELP <topic>".
250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao  To report bugs in the implementation send email to
260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao      sendmail-bugs@sendmail.org.
270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao  For local information send email to Postmaster at your site.
280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao  End of HELP info
290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao  >>> s.putcmd("vrfy","someone@here")
300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao  >>> s.getreply()
310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao  (250, "Somebody OverHere <somebody@here.my.org>")
320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao  >>> s.quit()
330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao'''
340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# Author: The Dragon De Monsyne <dragondm@integral.org>
360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# ESMTP support, test code and doc fixes added by
370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao#     Eric S. Raymond <esr@thyrsus.com>
380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# Better RFC 821 compliance (MAIL and RCPT, and CRLF in data)
390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao#     by Carey Evans <c.evans@clear.net.nz>, for picky mail servers.
400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# RFC 2554 (authentication) support by Gerhard Haering <gerhard@bigfoot.de>.
410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao#
420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# This was modified from the Python 1.5 library HTTP lib.
430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
440a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport socket
450a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport re
460a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport email.utils
470a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport base64
480a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport hmac
490a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom email.base64mime import encode as encode_base64
500a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom sys import stderr
510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao__all__ = ["SMTPException", "SMTPServerDisconnected", "SMTPResponseException",
530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao           "SMTPSenderRefused", "SMTPRecipientsRefused", "SMTPDataError",
540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao           "SMTPConnectError", "SMTPHeloError", "SMTPAuthenticationError",
550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao           "quoteaddr", "quotedata", "SMTP"]
560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
570a8c90248264a8b26970b4473770bcc3df8515fJosh GaoSMTP_PORT = 25
580a8c90248264a8b26970b4473770bcc3df8515fJosh GaoSMTP_SSL_PORT = 465
590a8c90248264a8b26970b4473770bcc3df8515fJosh GaoCRLF = "\r\n"
600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
610a8c90248264a8b26970b4473770bcc3df8515fJosh GaoOLDSTYLE_AUTH = re.compile(r"auth=(.*)", re.I)
620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# Exception classes used by this module.
650a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass SMTPException(Exception):
660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """Base class for all exceptions raised by this module."""
670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
680a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass SMTPServerDisconnected(SMTPException):
690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """Not connected to any SMTP server.
700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    This exception is raised when the server unexpectedly disconnects,
720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    or when an attempt is made to use the SMTP instance before
730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    connecting it to a server.
740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """
750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
760a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass SMTPResponseException(SMTPException):
770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """Base class for all exceptions that include an SMTP error code.
780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    These exceptions are generated in some instances when the SMTP
800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    server returns an error code.  The error code is stored in the
810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    `smtp_code' attribute of the error, and the `smtp_error' attribute
820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    is set to the error message.
830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """
840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def __init__(self, code, msg):
860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.smtp_code = code
870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.smtp_error = msg
880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.args = (code, msg)
890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
900a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass SMTPSenderRefused(SMTPResponseException):
910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """Sender address refused.
920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    In addition to the attributes set by on all SMTPResponseException
940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    exceptions, this sets `sender' to the string that the SMTP refused.
950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """
960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def __init__(self, code, msg, sender):
980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.smtp_code = code
990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.smtp_error = msg
1000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.sender = sender
1010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.args = (code, msg, sender)
1020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1030a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass SMTPRecipientsRefused(SMTPException):
1040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """All recipient addresses refused.
1050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    The errors for each recipient are accessible through the attribute
1070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    'recipients', which is a dictionary of exactly the same sort as
1080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    SMTP.sendmail() returns.
1090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """
1100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def __init__(self, recipients):
1120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.recipients = recipients
1130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.args = (recipients,)
1140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1160a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass SMTPDataError(SMTPResponseException):
1170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """The SMTP server didn't accept the data."""
1180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1190a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass SMTPConnectError(SMTPResponseException):
1200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """Error during connection establishment."""
1210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1220a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass SMTPHeloError(SMTPResponseException):
1230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """The server refused our HELO reply."""
1240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1250a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass SMTPAuthenticationError(SMTPResponseException):
1260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """Authentication error.
1270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    Most probably the server didn't accept the username/password
1290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    combination provided.
1300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """
1310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1330a8c90248264a8b26970b4473770bcc3df8515fJosh Gaodef quoteaddr(addr):
1340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """Quote a subset of the email addresses defined by RFC 821.
1350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    Should be able to handle anything rfc822.parseaddr can handle.
1370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """
1380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    m = (None, None)
1390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    try:
1400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        m = email.utils.parseaddr(addr)[1]
1410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    except AttributeError:
1420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        pass
1430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    if m == (None, None):  # Indicates parse failure or AttributeError
1440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # something weird here.. punt -ddm
1450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return "<%s>" % addr
1460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    elif m is None:
1470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # the sender wants an empty return address
1480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return "<>"
1490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    else:
1500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return "<%s>" % m
1510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1520a8c90248264a8b26970b4473770bcc3df8515fJosh Gaodef _addr_only(addrstring):
1530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    displayname, addr = email.utils.parseaddr(addrstring)
1540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    if (displayname, addr) == ('', ''):
1550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # parseaddr couldn't parse it, so use it as is.
1560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return addrstring
1570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    return addr
1580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1590a8c90248264a8b26970b4473770bcc3df8515fJosh Gaodef quotedata(data):
1600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """Quote data for email.
1610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    Double leading '.', and change Unix newline '\\n', or Mac '\\r' into
1630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    Internet CRLF end-of-line.
1640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """
1650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    return re.sub(r'(?m)^\.', '..',
1660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data))
1670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1690a8c90248264a8b26970b4473770bcc3df8515fJosh Gaotry:
1700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    import ssl
1710a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoexcept ImportError:
1720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    _have_ssl = False
1730a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoelse:
1740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    class SSLFakeFile:
1750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """A fake file like object that really wraps a SSLObject.
1760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        It only supports what is needed in smtplib.
1780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """
1790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        def __init__(self, sslobj):
1800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.sslobj = sslobj
1810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        def readline(self):
1830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            str = ""
1840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            chr = None
1850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            while chr != "\n":
1860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                chr = self.sslobj.read(1)
1870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                if not chr:
1880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    break
1890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                str += chr
1900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            return str
1910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        def close(self):
1930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            pass
1940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    _have_ssl = True
1960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1970a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass SMTP:
1980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """This class manages a connection to an SMTP or ESMTP server.
1990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    SMTP Objects:
2000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        SMTP objects have the following attributes:
2010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            helo_resp
2020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                This is the message given by the server in response to the
2030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                most recent HELO command.
2040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            ehlo_resp
2060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                This is the message given by the server in response to the
2070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                most recent EHLO command. This is usually multiline.
2080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            does_esmtp
2100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                This is a True value _after you do an EHLO command_, if the
2110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                server supports ESMTP.
2120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            esmtp_features
2140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                This is a dictionary, which, if the server supports ESMTP,
2150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                will _after you do an EHLO command_, contain the names of the
2160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                SMTP service extensions this server supports, and their
2170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                parameters (if any).
2180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                Note, all extension names are mapped to lower case in the
2200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                dictionary.
2210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        See each method's docstrings for details.  In general, there is a
2230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        method of the same name to perform each SMTP command.  There is also a
2240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        method called 'sendmail' that will do an entire mail transaction.
2250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """
2260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    debuglevel = 0
2270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    file = None
2280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    helo_resp = None
2290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    ehlo_msg = "ehlo"
2300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    ehlo_resp = None
2310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    does_esmtp = 0
2320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    default_port = SMTP_PORT
2330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def __init__(self, host='', port=0, local_hostname=None,
2350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
2360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Initialize a new instance.
2370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        If specified, `host' is the name of the remote host to which to
2390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        connect.  If specified, `port' specifies the port to which to connect.
2400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        By default, smtplib.SMTP_PORT is used.  If a host is specified the
2410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        connect method is called, and if it returns anything other than
2420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        a success code an SMTPConnectError is raised.  If specified,
2430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        `local_hostname` is used as the FQDN of the local host.  By default,
2440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        the local hostname is found using socket.getfqdn().
2450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """
2470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.timeout = timeout
2480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.esmtp_features = {}
2490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if host:
2500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            (code, msg) = self.connect(host, port)
2510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if code != 220:
2520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                raise SMTPConnectError(code, msg)
2530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if local_hostname is not None:
2540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.local_hostname = local_hostname
2550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        else:
2560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # RFC 2821 says we should use the fqdn in the EHLO/HELO verb, and
2570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # if that can't be calculated, that we should use a domain literal
2580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # instead (essentially an encoded IP address like [A.B.C.D]).
2590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            fqdn = socket.getfqdn()
2600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if '.' in fqdn:
2610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                self.local_hostname = fqdn
2620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            else:
2630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                # We can't find an fqdn hostname, so use a domain literal
2640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                addr = '127.0.0.1'
2650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                try:
2660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    addr = socket.gethostbyname(socket.gethostname())
2670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                except socket.gaierror:
2680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    pass
2690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                self.local_hostname = '[%s]' % addr
2700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def set_debuglevel(self, debuglevel):
2720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Set the debug output level.
2730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        A non-false value results in debug messages for connection and for all
2750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        messages sent to and received from the server.
2760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """
2780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.debuglevel = debuglevel
2790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def _get_socket(self, host, port, timeout):
2810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # This makes it simpler for SMTP_SSL to use the SMTP connect code
2820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # and just alter the socket connection bit.
2830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.debuglevel > 0:
2840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            print>>stderr, 'connect:', (host, port)
2850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return socket.create_connection((host, port), timeout)
2860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def connect(self, host='localhost', port=0):
2880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Connect to a host on a given port.
2890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        If the hostname ends with a colon (`:') followed by a number, and
2910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        there is no port specified, that suffix will be stripped off and the
2920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        number interpreted as the port number to use.
2930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        Note: This method is automatically invoked by __init__, if a host is
2950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        specified during instantiation.
2960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
2970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """
2980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if not port and (host.find(':') == host.rfind(':')):
2990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            i = host.rfind(':')
3000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if i >= 0:
3010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                host, port = host[:i], host[i + 1:]
3020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                try:
3030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    port = int(port)
3040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                except ValueError:
3050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    raise socket.error, "nonnumeric port"
3060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if not port:
3070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            port = self.default_port
3080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.debuglevel > 0:
3090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            print>>stderr, 'connect:', (host, port)
3100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.sock = self._get_socket(host, port, self.timeout)
3110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        (code, msg) = self.getreply()
3120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.debuglevel > 0:
3130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            print>>stderr, "connect:", msg
3140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return (code, msg)
3150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
3160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def send(self, str):
3170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Send `str' to the server."""
3180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.debuglevel > 0:
3190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            print>>stderr, 'send:', repr(str)
3200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if hasattr(self, 'sock') and self.sock:
3210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            try:
3220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                self.sock.sendall(str)
3230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            except socket.error:
3240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                self.close()
3250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                raise SMTPServerDisconnected('Server not connected')
3260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        else:
3270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            raise SMTPServerDisconnected('please run connect() first')
3280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
3290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def putcmd(self, cmd, args=""):
3300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Send a command to the server."""
3310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if args == "":
3320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            str = '%s%s' % (cmd, CRLF)
3330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        else:
3340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            str = '%s %s%s' % (cmd, args, CRLF)
3350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.send(str)
3360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
3370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def getreply(self):
3380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Get a reply from the server.
3390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
3400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        Returns a tuple consisting of:
3410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
3420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao          - server response code (e.g. '250', or such, if all goes well)
3430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            Note: returns -1 if it can't read response code.
3440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
3450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao          - server response string corresponding to response code (multiline
3460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            responses are converted to a single, multiline string).
3470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
3480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        Raises SMTPServerDisconnected if end-of-file is reached.
3490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """
3500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        resp = []
3510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.file is None:
3520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.file = self.sock.makefile('rb')
3530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        while 1:
3540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            try:
3550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                line = self.file.readline()
3560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            except socket.error as e:
3570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                self.close()
3580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                raise SMTPServerDisconnected("Connection unexpectedly closed: "
3590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                                             + str(e))
3600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if line == '':
3610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                self.close()
3620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                raise SMTPServerDisconnected("Connection unexpectedly closed")
3630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if self.debuglevel > 0:
3640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                print>>stderr, 'reply:', repr(line)
3650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            resp.append(line[4:].strip())
3660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            code = line[:3]
3670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # Check that the error code is syntactically correct.
3680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # Don't attempt to read a continuation line if it is broken.
3690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            try:
3700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                errcode = int(code)
3710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            except ValueError:
3720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                errcode = -1
3730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                break
3740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # Check if multiline response.
3750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if line[3:4] != "-":
3760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                break
3770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
3780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        errmsg = "\n".join(resp)
3790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.debuglevel > 0:
3800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            print>>stderr, 'reply: retcode (%s); Msg: %s' % (errcode, errmsg)
3810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return errcode, errmsg
3820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
3830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def docmd(self, cmd, args=""):
3840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Send a command, and return its response code."""
3850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.putcmd(cmd, args)
3860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return self.getreply()
3870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
3880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    # std smtp commands
3890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def helo(self, name=''):
3900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """SMTP 'helo' command.
3910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        Hostname to send for this command defaults to the FQDN of the local
3920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        host.
3930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """
3940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.putcmd("helo", name or self.local_hostname)
3950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        (code, msg) = self.getreply()
3960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.helo_resp = msg
3970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return (code, msg)
3980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
3990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def ehlo(self, name=''):
4000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """ SMTP 'ehlo' command.
4010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        Hostname to send for this command defaults to the FQDN of the local
4020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        host.
4030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """
4040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.esmtp_features = {}
4050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.putcmd(self.ehlo_msg, name or self.local_hostname)
4060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        (code, msg) = self.getreply()
4070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # According to RFC1869 some (badly written)
4080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # MTA's will disconnect on an ehlo. Toss an exception if
4090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # that happens -ddm
4100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if code == -1 and len(msg) == 0:
4110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.close()
4120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            raise SMTPServerDisconnected("Server not connected")
4130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.ehlo_resp = msg
4140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if code != 250:
4150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            return (code, msg)
4160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.does_esmtp = 1
4170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        #parse the ehlo response -ddm
4180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        resp = self.ehlo_resp.split('\n')
4190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        del resp[0]
4200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        for each in resp:
4210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # To be able to communicate with as many SMTP servers as possible,
4220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # we have to take the old-style auth advertisement into account,
4230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # because:
4240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # 1) Else our SMTP feature parser gets confused.
4250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # 2) There are some servers that only advertise the auth methods we
4260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            #    support using the old style.
4270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            auth_match = OLDSTYLE_AUTH.match(each)
4280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if auth_match:
4290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                # This doesn't remove duplicates, but that's no problem
4300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                self.esmtp_features["auth"] = self.esmtp_features.get("auth", "") \
4310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                        + " " + auth_match.groups(0)[0]
4320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                continue
4330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
4340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # RFC 1869 requires a space between ehlo keyword and parameters.
4350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # It's actually stricter, in that only spaces are allowed between
4360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # parameters, but were not going to check for that here.  Note
4370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # that the space isn't present if there are no parameters.
4380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            m = re.match(r'(?P<feature>[A-Za-z0-9][A-Za-z0-9\-]*) ?', each)
4390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if m:
4400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                feature = m.group("feature").lower()
4410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                params = m.string[m.end("feature"):].strip()
4420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                if feature == "auth":
4430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    self.esmtp_features[feature] = self.esmtp_features.get(feature, "") \
4440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                            + " " + params
4450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                else:
4460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    self.esmtp_features[feature] = params
4470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return (code, msg)
4480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
4490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def has_extn(self, opt):
4500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Does the server support a given SMTP service extension?"""
4510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return opt.lower() in self.esmtp_features
4520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
4530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def help(self, args=''):
4540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """SMTP 'help' command.
4550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        Returns help text from server."""
4560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.putcmd("help", args)
4570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return self.getreply()[1]
4580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
4590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def rset(self):
4600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """SMTP 'rset' command -- resets session."""
4610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return self.docmd("rset")
4620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
4630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def noop(self):
4640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """SMTP 'noop' command -- doesn't do anything :>"""
4650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return self.docmd("noop")
4660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
4670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def mail(self, sender, options=[]):
4680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """SMTP 'mail' command -- begins mail xfer session."""
4690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        optionlist = ''
4700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if options and self.does_esmtp:
4710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            optionlist = ' ' + ' '.join(options)
4720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.putcmd("mail", "FROM:%s%s" % (quoteaddr(sender), optionlist))
4730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return self.getreply()
4740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
4750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def rcpt(self, recip, options=[]):
4760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """SMTP 'rcpt' command -- indicates 1 recipient for this mail."""
4770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        optionlist = ''
4780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if options and self.does_esmtp:
4790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            optionlist = ' ' + ' '.join(options)
4800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.putcmd("rcpt", "TO:%s%s" % (quoteaddr(recip), optionlist))
4810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return self.getreply()
4820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
4830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def data(self, msg):
4840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """SMTP 'DATA' command -- sends message data to server.
4850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
4860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        Automatically quotes lines beginning with a period per rfc821.
4870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        Raises SMTPDataError if there is an unexpected reply to the
4880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        DATA command; the return value from this method is the final
4890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        response code received when the all data is sent.
4900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """
4910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.putcmd("data")
4920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        (code, repl) = self.getreply()
4930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.debuglevel > 0:
4940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            print>>stderr, "data:", (code, repl)
4950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if code != 354:
4960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            raise SMTPDataError(code, repl)
4970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        else:
4980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            q = quotedata(msg)
4990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if q[-2:] != CRLF:
5000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                q = q + CRLF
5010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            q = q + "." + CRLF
5020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.send(q)
5030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            (code, msg) = self.getreply()
5040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if self.debuglevel > 0:
5050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                print>>stderr, "data:", (code, msg)
5060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            return (code, msg)
5070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def verify(self, address):
5090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """SMTP 'verify' command -- checks for address validity."""
5100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.putcmd("vrfy", _addr_only(address))
5110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return self.getreply()
5120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    # a.k.a.
5130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    vrfy = verify
5140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def expn(self, address):
5160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """SMTP 'expn' command -- expands a mailing list."""
5170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.putcmd("expn", _addr_only(address))
5180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return self.getreply()
5190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    # some useful methods
5210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def ehlo_or_helo_if_needed(self):
5230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Call self.ehlo() and/or self.helo() if needed.
5240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        If there has been no previous EHLO or HELO command this session, this
5260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        method tries ESMTP EHLO first.
5270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        This method may raise the following exceptions:
5290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         SMTPHeloError            The server didn't reply properly to
5310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                                  the helo greeting.
5320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """
5330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.helo_resp is None and self.ehlo_resp is None:
5340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if not (200 <= self.ehlo()[0] <= 299):
5350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                (code, resp) = self.helo()
5360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                if not (200 <= code <= 299):
5370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    raise SMTPHeloError(code, resp)
5380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def login(self, user, password):
5400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Log in on an SMTP server that requires authentication.
5410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        The arguments are:
5430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            - user:     The user name to authenticate with.
5440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            - password: The password for the authentication.
5450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        If there has been no previous EHLO or HELO command this session, this
5470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        method tries ESMTP EHLO first.
5480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        This method will return normally if the authentication was successful.
5500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        This method may raise the following exceptions:
5520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         SMTPHeloError            The server didn't reply properly to
5540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                                  the helo greeting.
5550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         SMTPAuthenticationError  The server didn't accept the username/
5560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                                  password combination.
5570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         SMTPException            No suitable authentication method was
5580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                                  found.
5590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """
5600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        def encode_cram_md5(challenge, user, password):
5620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            challenge = base64.decodestring(challenge)
5630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            response = user + " " + hmac.HMAC(password, challenge).hexdigest()
5640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            return encode_base64(response, eol="")
5650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        def encode_plain(user, password):
5670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            return encode_base64("\0%s\0%s" % (user, password), eol="")
5680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        AUTH_PLAIN = "PLAIN"
5710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        AUTH_CRAM_MD5 = "CRAM-MD5"
5720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        AUTH_LOGIN = "LOGIN"
5730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.ehlo_or_helo_if_needed()
5750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if not self.has_extn("auth"):
5770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            raise SMTPException("SMTP AUTH extension not supported by server.")
5780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # Authentication methods the server supports:
5800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        authlist = self.esmtp_features["auth"].split()
5810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # List of authentication methods we support: from preferred to
5830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # less preferred methods. Except for the purpose of testing the weaker
5840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # ones, we prefer stronger methods like CRAM-MD5:
5850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN]
5860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # Determine the authentication method we'll use
5880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        authmethod = None
5890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        for method in preferred_auths:
5900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if method in authlist:
5910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                authmethod = method
5920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                break
5930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
5940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if authmethod == AUTH_CRAM_MD5:
5950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            (code, resp) = self.docmd("AUTH", AUTH_CRAM_MD5)
5960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if code == 503:
5970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                # 503 == 'Error: already authenticated'
5980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                return (code, resp)
5990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            (code, resp) = self.docmd(encode_cram_md5(resp, user, password))
6000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        elif authmethod == AUTH_PLAIN:
6010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            (code, resp) = self.docmd("AUTH",
6020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                AUTH_PLAIN + " " + encode_plain(user, password))
6030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        elif authmethod == AUTH_LOGIN:
6040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            (code, resp) = self.docmd("AUTH",
6050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                "%s %s" % (AUTH_LOGIN, encode_base64(user, eol="")))
6060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if code != 334:
6070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                raise SMTPAuthenticationError(code, resp)
6080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            (code, resp) = self.docmd(encode_base64(password, eol=""))
6090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        elif authmethod is None:
6100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            raise SMTPException("No suitable authentication method found.")
6110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if code not in (235, 503):
6120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # 235 == 'Authentication successful'
6130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # 503 == 'Error: already authenticated'
6140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            raise SMTPAuthenticationError(code, resp)
6150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return (code, resp)
6160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
6170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def starttls(self, keyfile=None, certfile=None):
6180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Puts the connection to the SMTP server into TLS mode.
6190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
6200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        If there has been no previous EHLO or HELO command this session, this
6210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        method tries ESMTP EHLO first.
6220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
6230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        If the server supports TLS, this will encrypt the rest of the SMTP
6240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        session. If you provide the keyfile and certfile parameters,
6250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        the identity of the SMTP server and client can be checked. This,
6260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        however, depends on whether the socket module really checks the
6270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        certificates.
6280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
6290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        This method may raise the following exceptions:
6300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
6310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         SMTPHeloError            The server didn't reply properly to
6320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                                  the helo greeting.
6330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """
6340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.ehlo_or_helo_if_needed()
6350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if not self.has_extn("starttls"):
6360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            raise SMTPException("STARTTLS extension not supported by server.")
6370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        (resp, reply) = self.docmd("STARTTLS")
6380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if resp == 220:
6390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if not _have_ssl:
6400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                raise RuntimeError("No SSL support included in this Python")
6410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.sock = ssl.wrap_socket(self.sock, keyfile, certfile)
6420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.file = SSLFakeFile(self.sock)
6430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # RFC 3207:
6440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # The client MUST discard any knowledge obtained from
6450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # the server, such as the list of SMTP service extensions,
6460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # which was not obtained from the TLS negotiation itself.
6470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.helo_resp = None
6480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.ehlo_resp = None
6490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.esmtp_features = {}
6500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.does_esmtp = 0
6510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return (resp, reply)
6520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
6530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def sendmail(self, from_addr, to_addrs, msg, mail_options=[],
6540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                 rcpt_options=[]):
6550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """This command performs an entire mail transaction.
6560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
6570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        The arguments are:
6580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            - from_addr    : The address sending this mail.
6590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            - to_addrs     : A list of addresses to send this mail to.  A bare
6600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                             string will be treated as a list with 1 address.
6610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            - msg          : The message to send.
6620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            - mail_options : List of ESMTP options (such as 8bitmime) for the
6630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                             mail command.
6640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            - rcpt_options : List of ESMTP options (such as DSN commands) for
6650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                             all the rcpt commands.
6660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
6670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        If there has been no previous EHLO or HELO command this session, this
6680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        method tries ESMTP EHLO first.  If the server does ESMTP, message size
6690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        and each of the specified options will be passed to it.  If EHLO
6700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        fails, HELO will be tried and ESMTP options suppressed.
6710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
6720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        This method will return normally if the mail is accepted for at least
6730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        one recipient.  It returns a dictionary, with one entry for each
6740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        recipient that was refused.  Each entry contains a tuple of the SMTP
6750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        error code and the accompanying error message sent by the server.
6760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
6770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        This method may raise the following exceptions:
6780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
6790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         SMTPHeloError          The server didn't reply properly to
6800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                                the helo greeting.
6810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         SMTPRecipientsRefused  The server rejected ALL recipients
6820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                                (no mail was sent).
6830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         SMTPSenderRefused      The server didn't accept the from_addr.
6840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         SMTPDataError          The server replied with an unexpected
6850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                                error code (other than a refusal of
6860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                                a recipient).
6870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
6880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        Note: the connection will be open even after an exception is raised.
6890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
6900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        Example:
6910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
6920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         >>> import smtplib
6930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         >>> s=smtplib.SMTP("localhost")
6940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         >>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]
6950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         >>> msg = '''\\
6960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         ... From: Me@my.org
6970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         ... Subject: testin'...
6980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         ...
6990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         ... This is a test '''
7000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         >>> s.sendmail("me@my.org",tolist,msg)
7010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         { "three@three.org" : ( 550 ,"User unknown" ) }
7020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao         >>> s.quit()
7030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        In the above example, the message was accepted for delivery to three
7050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        of the four addresses, and one was rejected, with the error code
7060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        550.  If all addresses are accepted, then the method will return an
7070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        empty dictionary.
7080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """
7100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.ehlo_or_helo_if_needed()
7110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        esmtp_opts = []
7120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.does_esmtp:
7130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # Hmmm? what's this? -ddm
7140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # self.esmtp_features['7bit']=""
7150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if self.has_extn('size'):
7160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                esmtp_opts.append("size=%d" % len(msg))
7170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            for option in mail_options:
7180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                esmtp_opts.append(option)
7190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        (code, resp) = self.mail(from_addr, esmtp_opts)
7210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if code != 250:
7220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.rset()
7230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            raise SMTPSenderRefused(code, resp, from_addr)
7240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        senderrs = {}
7250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if isinstance(to_addrs, basestring):
7260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            to_addrs = [to_addrs]
7270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        for each in to_addrs:
7280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            (code, resp) = self.rcpt(each, rcpt_options)
7290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if (code != 250) and (code != 251):
7300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                senderrs[each] = (code, resp)
7310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if len(senderrs) == len(to_addrs):
7320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # the server refused all our recipients
7330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.rset()
7340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            raise SMTPRecipientsRefused(senderrs)
7350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        (code, resp) = self.data(msg)
7360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if code != 250:
7370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.rset()
7380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            raise SMTPDataError(code, resp)
7390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        #if we got here then somebody got our mail
7400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return senderrs
7410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def close(self):
7440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Close the connection to the SMTP server."""
7450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.file:
7460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.file.close()
7470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.file = None
7480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.sock:
7490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.sock.close()
7500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.sock = None
7510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def quit(self):
7540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Terminate the SMTP session."""
7550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        res = self.docmd("quit")
7560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.close()
7570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return res
7580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7590a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoif _have_ssl:
7600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    class SMTP_SSL(SMTP):
7620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """ This is a subclass derived from SMTP that connects over an SSL encrypted
7630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        socket (to use this class you need a socket module that was compiled with SSL
7640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        support). If host is not specified, '' (the local host) is used. If port is
7650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        omitted, the standard SMTP-over-SSL port (465) is used. keyfile and certfile
7660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        are also optional - they can contain a PEM formatted private key and
7670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        certificate chain file for the SSL connection.
7680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """
7690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        default_port = SMTP_SSL_PORT
7710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        def __init__(self, host='', port=0, local_hostname=None,
7730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                     keyfile=None, certfile=None,
7740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                     timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
7750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.keyfile = keyfile
7760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.certfile = certfile
7770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            SMTP.__init__(self, host, port, local_hostname, timeout)
7780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        def _get_socket(self, host, port, timeout):
7800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if self.debuglevel > 0:
7810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                print>>stderr, 'connect:', (host, port)
7820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            new_socket = socket.create_connection((host, port), timeout)
7830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            new_socket = ssl.wrap_socket(new_socket, self.keyfile, self.certfile)
7840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.file = SSLFakeFile(new_socket)
7850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            return new_socket
7860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    __all__.append("SMTP_SSL")
7880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao#
7900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# LMTP extension
7910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao#
7920a8c90248264a8b26970b4473770bcc3df8515fJosh GaoLMTP_PORT = 2003
7930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7940a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass LMTP(SMTP):
7950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """LMTP - Local Mail Transfer Protocol
7960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
7970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    The LMTP protocol, which is very similar to ESMTP, is heavily based
7980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    on the standard SMTP client. It's common to use Unix sockets for LMTP,
7990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    so our connect() method must support that as well as a regular
8000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    host:port server. To specify a Unix socket, you must use an absolute
8010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    path as the host, starting with a '/'.
8020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
8030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    Authentication is supported, using the regular SMTP mechanism. When
8040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    using a Unix socket, LMTP generally don't support or require any
8050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    authentication, but your mileage might vary."""
8060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
8070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    ehlo_msg = "lhlo"
8080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
8090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def __init__(self, host='', port=LMTP_PORT, local_hostname=None):
8100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Initialize a new instance."""
8110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        SMTP.__init__(self, host, port, local_hostname)
8120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
8130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def connect(self, host='localhost', port=0):
8140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        """Connect to the LMTP daemon, on either a Unix or a TCP socket."""
8150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if host[0] != '/':
8160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            return SMTP.connect(self, host, port)
8170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
8180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # Handle Unix-domain sockets.
8190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        try:
8200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
8210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.sock.connect(host)
8220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        except socket.error:
8230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if self.debuglevel > 0:
8240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                print>>stderr, 'connect fail:', host
8250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if self.sock:
8260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                self.sock.close()
8270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.sock = None
8280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            raise
8290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        (code, msg) = self.getreply()
8300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.debuglevel > 0:
8310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            print>>stderr, "connect:", msg
8320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return (code, msg)
8330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
8340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
8350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# Test the sendmail method, which tests most of the others.
8360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# Note: This always sends to localhost.
8370a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoif __name__ == '__main__':
8380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    import sys
8390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
8400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def prompt(prompt):
8410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        sys.stdout.write(prompt + ": ")
8420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return sys.stdin.readline().strip()
8430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
8440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    fromaddr = prompt("From")
8450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    toaddrs = prompt("To").split(',')
8460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    print "Enter message, end with ^D:"
8470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    msg = ''
8480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    while 1:
8490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        line = sys.stdin.readline()
8500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if not line:
8510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            break
8520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        msg = msg + line
8530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    print "Message length is %d" % len(msg)
8540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
8550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    server = SMTP('localhost')
8560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    server.set_debuglevel(1)
8570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    server.sendmail(fromaddr, toaddrs, msg)
8580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    server.quit()
859