Edit File by line
/home/barbar84/public_h.../wp-conte.../plugins/sujqvwi/ShExBy/shex_roo.../lib64/python2....
File: smtplib.py
#! /usr/bin/python2.7
[0] Fix | Delete
[1] Fix | Delete
'''SMTP/ESMTP client class.
[2] Fix | Delete
[3] Fix | Delete
This should follow RFC 821 (SMTP), RFC 1869 (ESMTP), RFC 2554 (SMTP
[4] Fix | Delete
Authentication) and RFC 2487 (Secure SMTP over TLS).
[5] Fix | Delete
[6] Fix | Delete
Notes:
[7] Fix | Delete
[8] Fix | Delete
Please remember, when doing ESMTP, that the names of the SMTP service
[9] Fix | Delete
extensions are NOT the same thing as the option keywords for the RCPT
[10] Fix | Delete
and MAIL commands!
[11] Fix | Delete
[12] Fix | Delete
Example:
[13] Fix | Delete
[14] Fix | Delete
>>> import smtplib
[15] Fix | Delete
>>> s=smtplib.SMTP("localhost")
[16] Fix | Delete
>>> print s.help()
[17] Fix | Delete
This is Sendmail version 8.8.4
[18] Fix | Delete
Topics:
[19] Fix | Delete
HELO EHLO MAIL RCPT DATA
[20] Fix | Delete
RSET NOOP QUIT HELP VRFY
[21] Fix | Delete
EXPN VERB ETRN DSN
[22] Fix | Delete
For more info use "HELP <topic>".
[23] Fix | Delete
To report bugs in the implementation send email to
[24] Fix | Delete
sendmail-bugs@sendmail.org.
[25] Fix | Delete
For local information send email to Postmaster at your site.
[26] Fix | Delete
End of HELP info
[27] Fix | Delete
>>> s.putcmd("vrfy","someone@here")
[28] Fix | Delete
>>> s.getreply()
[29] Fix | Delete
(250, "Somebody OverHere <somebody@here.my.org>")
[30] Fix | Delete
>>> s.quit()
[31] Fix | Delete
'''
[32] Fix | Delete
[33] Fix | Delete
# Author: The Dragon De Monsyne <dragondm@integral.org>
[34] Fix | Delete
# ESMTP support, test code and doc fixes added by
[35] Fix | Delete
# Eric S. Raymond <esr@thyrsus.com>
[36] Fix | Delete
# Better RFC 821 compliance (MAIL and RCPT, and CRLF in data)
[37] Fix | Delete
# by Carey Evans <c.evans@clear.net.nz>, for picky mail servers.
[38] Fix | Delete
# RFC 2554 (authentication) support by Gerhard Haering <gerhard@bigfoot.de>.
[39] Fix | Delete
#
[40] Fix | Delete
# This was modified from the Python 1.5 library HTTP lib.
[41] Fix | Delete
[42] Fix | Delete
import socket
[43] Fix | Delete
import re
[44] Fix | Delete
import email.utils
[45] Fix | Delete
import base64
[46] Fix | Delete
import hmac
[47] Fix | Delete
from email.base64mime import encode as encode_base64
[48] Fix | Delete
from sys import stderr
[49] Fix | Delete
[50] Fix | Delete
__all__ = ["SMTPException", "SMTPServerDisconnected", "SMTPResponseException",
[51] Fix | Delete
"SMTPSenderRefused", "SMTPRecipientsRefused", "SMTPDataError",
[52] Fix | Delete
"SMTPConnectError", "SMTPHeloError", "SMTPAuthenticationError",
[53] Fix | Delete
"quoteaddr", "quotedata", "SMTP"]
[54] Fix | Delete
[55] Fix | Delete
SMTP_PORT = 25
[56] Fix | Delete
SMTP_SSL_PORT = 465
[57] Fix | Delete
CRLF = "\r\n"
[58] Fix | Delete
_MAXLINE = 8192 # more than 8 times larger than RFC 821, 4.5.3
[59] Fix | Delete
[60] Fix | Delete
OLDSTYLE_AUTH = re.compile(r"auth=(.*)", re.I)
[61] Fix | Delete
[62] Fix | Delete
[63] Fix | Delete
# Exception classes used by this module.
[64] Fix | Delete
class SMTPException(Exception):
[65] Fix | Delete
"""Base class for all exceptions raised by this module."""
[66] Fix | Delete
[67] Fix | Delete
class SMTPServerDisconnected(SMTPException):
[68] Fix | Delete
"""Not connected to any SMTP server.
[69] Fix | Delete
[70] Fix | Delete
This exception is raised when the server unexpectedly disconnects,
[71] Fix | Delete
or when an attempt is made to use the SMTP instance before
[72] Fix | Delete
connecting it to a server.
[73] Fix | Delete
"""
[74] Fix | Delete
[75] Fix | Delete
class SMTPResponseException(SMTPException):
[76] Fix | Delete
"""Base class for all exceptions that include an SMTP error code.
[77] Fix | Delete
[78] Fix | Delete
These exceptions are generated in some instances when the SMTP
[79] Fix | Delete
server returns an error code. The error code is stored in the
[80] Fix | Delete
`smtp_code' attribute of the error, and the `smtp_error' attribute
[81] Fix | Delete
is set to the error message.
[82] Fix | Delete
"""
[83] Fix | Delete
[84] Fix | Delete
def __init__(self, code, msg):
[85] Fix | Delete
self.smtp_code = code
[86] Fix | Delete
self.smtp_error = msg
[87] Fix | Delete
self.args = (code, msg)
[88] Fix | Delete
[89] Fix | Delete
class SMTPSenderRefused(SMTPResponseException):
[90] Fix | Delete
"""Sender address refused.
[91] Fix | Delete
[92] Fix | Delete
In addition to the attributes set by on all SMTPResponseException
[93] Fix | Delete
exceptions, this sets `sender' to the string that the SMTP refused.
[94] Fix | Delete
"""
[95] Fix | Delete
[96] Fix | Delete
def __init__(self, code, msg, sender):
[97] Fix | Delete
self.smtp_code = code
[98] Fix | Delete
self.smtp_error = msg
[99] Fix | Delete
self.sender = sender
[100] Fix | Delete
self.args = (code, msg, sender)
[101] Fix | Delete
[102] Fix | Delete
class SMTPRecipientsRefused(SMTPException):
[103] Fix | Delete
"""All recipient addresses refused.
[104] Fix | Delete
[105] Fix | Delete
The errors for each recipient are accessible through the attribute
[106] Fix | Delete
'recipients', which is a dictionary of exactly the same sort as
[107] Fix | Delete
SMTP.sendmail() returns.
[108] Fix | Delete
"""
[109] Fix | Delete
[110] Fix | Delete
def __init__(self, recipients):
[111] Fix | Delete
self.recipients = recipients
[112] Fix | Delete
self.args = (recipients,)
[113] Fix | Delete
[114] Fix | Delete
[115] Fix | Delete
class SMTPDataError(SMTPResponseException):
[116] Fix | Delete
"""The SMTP server didn't accept the data."""
[117] Fix | Delete
[118] Fix | Delete
class SMTPConnectError(SMTPResponseException):
[119] Fix | Delete
"""Error during connection establishment."""
[120] Fix | Delete
[121] Fix | Delete
class SMTPHeloError(SMTPResponseException):
[122] Fix | Delete
"""The server refused our HELO reply."""
[123] Fix | Delete
[124] Fix | Delete
class SMTPAuthenticationError(SMTPResponseException):
[125] Fix | Delete
"""Authentication error.
[126] Fix | Delete
[127] Fix | Delete
Most probably the server didn't accept the username/password
[128] Fix | Delete
combination provided.
[129] Fix | Delete
"""
[130] Fix | Delete
[131] Fix | Delete
[132] Fix | Delete
def quoteaddr(addr):
[133] Fix | Delete
"""Quote a subset of the email addresses defined by RFC 821.
[134] Fix | Delete
[135] Fix | Delete
Should be able to handle anything rfc822.parseaddr can handle.
[136] Fix | Delete
"""
[137] Fix | Delete
m = (None, None)
[138] Fix | Delete
try:
[139] Fix | Delete
m = email.utils.parseaddr(addr)[1]
[140] Fix | Delete
except AttributeError:
[141] Fix | Delete
pass
[142] Fix | Delete
if m == (None, None): # Indicates parse failure or AttributeError
[143] Fix | Delete
# something weird here.. punt -ddm
[144] Fix | Delete
return "<%s>" % addr
[145] Fix | Delete
elif m is None:
[146] Fix | Delete
# the sender wants an empty return address
[147] Fix | Delete
return "<>"
[148] Fix | Delete
else:
[149] Fix | Delete
return "<%s>" % m
[150] Fix | Delete
[151] Fix | Delete
def _addr_only(addrstring):
[152] Fix | Delete
displayname, addr = email.utils.parseaddr(addrstring)
[153] Fix | Delete
if (displayname, addr) == ('', ''):
[154] Fix | Delete
# parseaddr couldn't parse it, so use it as is.
[155] Fix | Delete
return addrstring
[156] Fix | Delete
return addr
[157] Fix | Delete
[158] Fix | Delete
def quotedata(data):
[159] Fix | Delete
"""Quote data for email.
[160] Fix | Delete
[161] Fix | Delete
Double leading '.', and change Unix newline '\\n', or Mac '\\r' into
[162] Fix | Delete
Internet CRLF end-of-line.
[163] Fix | Delete
"""
[164] Fix | Delete
return re.sub(r'(?m)^\.', '..',
[165] Fix | Delete
re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data))
[166] Fix | Delete
[167] Fix | Delete
[168] Fix | Delete
try:
[169] Fix | Delete
import ssl
[170] Fix | Delete
except ImportError:
[171] Fix | Delete
_have_ssl = False
[172] Fix | Delete
else:
[173] Fix | Delete
class SSLFakeFile:
[174] Fix | Delete
"""A fake file like object that really wraps a SSLObject.
[175] Fix | Delete
[176] Fix | Delete
It only supports what is needed in smtplib.
[177] Fix | Delete
"""
[178] Fix | Delete
def __init__(self, sslobj):
[179] Fix | Delete
self.sslobj = sslobj
[180] Fix | Delete
[181] Fix | Delete
def readline(self, size=-1):
[182] Fix | Delete
if size < 0:
[183] Fix | Delete
size = None
[184] Fix | Delete
str = ""
[185] Fix | Delete
chr = None
[186] Fix | Delete
while chr != "\n":
[187] Fix | Delete
if size is not None and len(str) >= size:
[188] Fix | Delete
break
[189] Fix | Delete
chr = self.sslobj.read(1)
[190] Fix | Delete
if not chr:
[191] Fix | Delete
break
[192] Fix | Delete
str += chr
[193] Fix | Delete
return str
[194] Fix | Delete
[195] Fix | Delete
def close(self):
[196] Fix | Delete
pass
[197] Fix | Delete
[198] Fix | Delete
_have_ssl = True
[199] Fix | Delete
[200] Fix | Delete
class SMTP:
[201] Fix | Delete
"""This class manages a connection to an SMTP or ESMTP server.
[202] Fix | Delete
SMTP Objects:
[203] Fix | Delete
SMTP objects have the following attributes:
[204] Fix | Delete
helo_resp
[205] Fix | Delete
This is the message given by the server in response to the
[206] Fix | Delete
most recent HELO command.
[207] Fix | Delete
[208] Fix | Delete
ehlo_resp
[209] Fix | Delete
This is the message given by the server in response to the
[210] Fix | Delete
most recent EHLO command. This is usually multiline.
[211] Fix | Delete
[212] Fix | Delete
does_esmtp
[213] Fix | Delete
This is a True value _after you do an EHLO command_, if the
[214] Fix | Delete
server supports ESMTP.
[215] Fix | Delete
[216] Fix | Delete
esmtp_features
[217] Fix | Delete
This is a dictionary, which, if the server supports ESMTP,
[218] Fix | Delete
will _after you do an EHLO command_, contain the names of the
[219] Fix | Delete
SMTP service extensions this server supports, and their
[220] Fix | Delete
parameters (if any).
[221] Fix | Delete
[222] Fix | Delete
Note, all extension names are mapped to lower case in the
[223] Fix | Delete
dictionary.
[224] Fix | Delete
[225] Fix | Delete
See each method's docstrings for details. In general, there is a
[226] Fix | Delete
method of the same name to perform each SMTP command. There is also a
[227] Fix | Delete
method called 'sendmail' that will do an entire mail transaction.
[228] Fix | Delete
"""
[229] Fix | Delete
debuglevel = 0
[230] Fix | Delete
file = None
[231] Fix | Delete
helo_resp = None
[232] Fix | Delete
ehlo_msg = "ehlo"
[233] Fix | Delete
ehlo_resp = None
[234] Fix | Delete
does_esmtp = 0
[235] Fix | Delete
default_port = SMTP_PORT
[236] Fix | Delete
[237] Fix | Delete
def __init__(self, host='', port=0, local_hostname=None,
[238] Fix | Delete
timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
[239] Fix | Delete
"""Initialize a new instance.
[240] Fix | Delete
[241] Fix | Delete
If specified, `host' is the name of the remote host to which to
[242] Fix | Delete
connect. If specified, `port' specifies the port to which to connect.
[243] Fix | Delete
By default, smtplib.SMTP_PORT is used. If a host is specified the
[244] Fix | Delete
connect method is called, and if it returns anything other than a
[245] Fix | Delete
success code an SMTPConnectError is raised. If specified,
[246] Fix | Delete
`local_hostname` is used as the FQDN of the local host for the
[247] Fix | Delete
HELO/EHLO command. Otherwise, the local hostname is found using
[248] Fix | Delete
socket.getfqdn().
[249] Fix | Delete
[250] Fix | Delete
"""
[251] Fix | Delete
self.timeout = timeout
[252] Fix | Delete
self.esmtp_features = {}
[253] Fix | Delete
if host:
[254] Fix | Delete
(code, msg) = self.connect(host, port)
[255] Fix | Delete
if code != 220:
[256] Fix | Delete
self.close()
[257] Fix | Delete
raise SMTPConnectError(code, msg)
[258] Fix | Delete
if local_hostname is not None:
[259] Fix | Delete
self.local_hostname = local_hostname
[260] Fix | Delete
else:
[261] Fix | Delete
# RFC 2821 says we should use the fqdn in the EHLO/HELO verb, and
[262] Fix | Delete
# if that can't be calculated, that we should use a domain literal
[263] Fix | Delete
# instead (essentially an encoded IP address like [A.B.C.D]).
[264] Fix | Delete
fqdn = socket.getfqdn()
[265] Fix | Delete
if '.' in fqdn:
[266] Fix | Delete
self.local_hostname = fqdn
[267] Fix | Delete
else:
[268] Fix | Delete
# We can't find an fqdn hostname, so use a domain literal
[269] Fix | Delete
addr = '127.0.0.1'
[270] Fix | Delete
try:
[271] Fix | Delete
addr = socket.gethostbyname(socket.gethostname())
[272] Fix | Delete
except socket.gaierror:
[273] Fix | Delete
pass
[274] Fix | Delete
self.local_hostname = '[%s]' % addr
[275] Fix | Delete
[276] Fix | Delete
def set_debuglevel(self, debuglevel):
[277] Fix | Delete
"""Set the debug output level.
[278] Fix | Delete
[279] Fix | Delete
A non-false value results in debug messages for connection and for all
[280] Fix | Delete
messages sent to and received from the server.
[281] Fix | Delete
[282] Fix | Delete
"""
[283] Fix | Delete
self.debuglevel = debuglevel
[284] Fix | Delete
[285] Fix | Delete
def _get_socket(self, host, port, timeout):
[286] Fix | Delete
# This makes it simpler for SMTP_SSL to use the SMTP connect code
[287] Fix | Delete
# and just alter the socket connection bit.
[288] Fix | Delete
if self.debuglevel > 0:
[289] Fix | Delete
print>>stderr, 'connect:', (host, port)
[290] Fix | Delete
return socket.create_connection((host, port), timeout)
[291] Fix | Delete
[292] Fix | Delete
def connect(self, host='localhost', port=0):
[293] Fix | Delete
"""Connect to a host on a given port.
[294] Fix | Delete
[295] Fix | Delete
If the hostname ends with a colon (`:') followed by a number, and
[296] Fix | Delete
there is no port specified, that suffix will be stripped off and the
[297] Fix | Delete
number interpreted as the port number to use.
[298] Fix | Delete
[299] Fix | Delete
Note: This method is automatically invoked by __init__, if a host is
[300] Fix | Delete
specified during instantiation.
[301] Fix | Delete
[302] Fix | Delete
"""
[303] Fix | Delete
if not port and (host.find(':') == host.rfind(':')):
[304] Fix | Delete
i = host.rfind(':')
[305] Fix | Delete
if i >= 0:
[306] Fix | Delete
host, port = host[:i], host[i + 1:]
[307] Fix | Delete
try:
[308] Fix | Delete
port = int(port)
[309] Fix | Delete
except ValueError:
[310] Fix | Delete
raise socket.error, "nonnumeric port"
[311] Fix | Delete
if not port:
[312] Fix | Delete
port = self.default_port
[313] Fix | Delete
if self.debuglevel > 0:
[314] Fix | Delete
print>>stderr, 'connect:', (host, port)
[315] Fix | Delete
self.sock = self._get_socket(host, port, self.timeout)
[316] Fix | Delete
(code, msg) = self.getreply()
[317] Fix | Delete
if self.debuglevel > 0:
[318] Fix | Delete
print>>stderr, "connect:", msg
[319] Fix | Delete
return (code, msg)
[320] Fix | Delete
[321] Fix | Delete
def send(self, str):
[322] Fix | Delete
"""Send `str' to the server."""
[323] Fix | Delete
if self.debuglevel > 0:
[324] Fix | Delete
print>>stderr, 'send:', repr(str)
[325] Fix | Delete
if hasattr(self, 'sock') and self.sock:
[326] Fix | Delete
try:
[327] Fix | Delete
self.sock.sendall(str)
[328] Fix | Delete
except socket.error:
[329] Fix | Delete
self.close()
[330] Fix | Delete
raise SMTPServerDisconnected('Server not connected')
[331] Fix | Delete
else:
[332] Fix | Delete
raise SMTPServerDisconnected('please run connect() first')
[333] Fix | Delete
[334] Fix | Delete
def putcmd(self, cmd, args=""):
[335] Fix | Delete
"""Send a command to the server."""
[336] Fix | Delete
if args == "":
[337] Fix | Delete
str = '%s%s' % (cmd, CRLF)
[338] Fix | Delete
else:
[339] Fix | Delete
str = '%s %s%s' % (cmd, args, CRLF)
[340] Fix | Delete
self.send(str)
[341] Fix | Delete
[342] Fix | Delete
def getreply(self):
[343] Fix | Delete
"""Get a reply from the server.
[344] Fix | Delete
[345] Fix | Delete
Returns a tuple consisting of:
[346] Fix | Delete
[347] Fix | Delete
- server response code (e.g. '250', or such, if all goes well)
[348] Fix | Delete
Note: returns -1 if it can't read response code.
[349] Fix | Delete
[350] Fix | Delete
- server response string corresponding to response code (multiline
[351] Fix | Delete
responses are converted to a single, multiline string).
[352] Fix | Delete
[353] Fix | Delete
Raises SMTPServerDisconnected if end-of-file is reached.
[354] Fix | Delete
"""
[355] Fix | Delete
resp = []
[356] Fix | Delete
if self.file is None:
[357] Fix | Delete
self.file = self.sock.makefile('rb')
[358] Fix | Delete
while 1:
[359] Fix | Delete
try:
[360] Fix | Delete
line = self.file.readline(_MAXLINE + 1)
[361] Fix | Delete
except socket.error as e:
[362] Fix | Delete
self.close()
[363] Fix | Delete
raise SMTPServerDisconnected("Connection unexpectedly closed: "
[364] Fix | Delete
+ str(e))
[365] Fix | Delete
if line == '':
[366] Fix | Delete
self.close()
[367] Fix | Delete
raise SMTPServerDisconnected("Connection unexpectedly closed")
[368] Fix | Delete
if self.debuglevel > 0:
[369] Fix | Delete
print>>stderr, 'reply:', repr(line)
[370] Fix | Delete
if len(line) > _MAXLINE:
[371] Fix | Delete
raise SMTPResponseException(500, "Line too long.")
[372] Fix | Delete
resp.append(line[4:].strip())
[373] Fix | Delete
code = line[:3]
[374] Fix | Delete
# Check that the error code is syntactically correct.
[375] Fix | Delete
# Don't attempt to read a continuation line if it is broken.
[376] Fix | Delete
try:
[377] Fix | Delete
errcode = int(code)
[378] Fix | Delete
except ValueError:
[379] Fix | Delete
errcode = -1
[380] Fix | Delete
break
[381] Fix | Delete
# Check if multiline response.
[382] Fix | Delete
if line[3:4] != "-":
[383] Fix | Delete
break
[384] Fix | Delete
[385] Fix | Delete
errmsg = "\n".join(resp)
[386] Fix | Delete
if self.debuglevel > 0:
[387] Fix | Delete
print>>stderr, 'reply: retcode (%s); Msg: %s' % (errcode, errmsg)
[388] Fix | Delete
return errcode, errmsg
[389] Fix | Delete
[390] Fix | Delete
def docmd(self, cmd, args=""):
[391] Fix | Delete
"""Send a command, and return its response code."""
[392] Fix | Delete
self.putcmd(cmd, args)
[393] Fix | Delete
return self.getreply()
[394] Fix | Delete
[395] Fix | Delete
# std smtp commands
[396] Fix | Delete
def helo(self, name=''):
[397] Fix | Delete
"""SMTP 'helo' command.
[398] Fix | Delete
Hostname to send for this command defaults to the FQDN of the local
[399] Fix | Delete
host.
[400] Fix | Delete
"""
[401] Fix | Delete
self.putcmd("helo", name or self.local_hostname)
[402] Fix | Delete
(code, msg) = self.getreply()
[403] Fix | Delete
self.helo_resp = msg
[404] Fix | Delete
return (code, msg)
[405] Fix | Delete
[406] Fix | Delete
def ehlo(self, name=''):
[407] Fix | Delete
""" SMTP 'ehlo' command.
[408] Fix | Delete
Hostname to send for this command defaults to the FQDN of the local
[409] Fix | Delete
host.
[410] Fix | Delete
"""
[411] Fix | Delete
self.esmtp_features = {}
[412] Fix | Delete
self.putcmd(self.ehlo_msg, name or self.local_hostname)
[413] Fix | Delete
(code, msg) = self.getreply()
[414] Fix | Delete
# According to RFC1869 some (badly written)
[415] Fix | Delete
# MTA's will disconnect on an ehlo. Toss an exception if
[416] Fix | Delete
# that happens -ddm
[417] Fix | Delete
if code == -1 and len(msg) == 0:
[418] Fix | Delete
self.close()
[419] Fix | Delete
raise SMTPServerDisconnected("Server not connected")
[420] Fix | Delete
self.ehlo_resp = msg
[421] Fix | Delete
if code != 250:
[422] Fix | Delete
return (code, msg)
[423] Fix | Delete
self.does_esmtp = 1
[424] Fix | Delete
#parse the ehlo response -ddm
[425] Fix | Delete
resp = self.ehlo_resp.split('\n')
[426] Fix | Delete
del resp[0]
[427] Fix | Delete
for each in resp:
[428] Fix | Delete
# To be able to communicate with as many SMTP servers as possible,
[429] Fix | Delete
# we have to take the old-style auth advertisement into account,
[430] Fix | Delete
# because:
[431] Fix | Delete
# 1) Else our SMTP feature parser gets confused.
[432] Fix | Delete
# 2) There are some servers that only advertise the auth methods we
[433] Fix | Delete
# support using the old style.
[434] Fix | Delete
auth_match = OLDSTYLE_AUTH.match(each)
[435] Fix | Delete
if auth_match:
[436] Fix | Delete
# This doesn't remove duplicates, but that's no problem
[437] Fix | Delete
self.esmtp_features["auth"] = self.esmtp_features.get("auth", "") \
[438] Fix | Delete
+ " " + auth_match.groups(0)[0]
[439] Fix | Delete
continue
[440] Fix | Delete
[441] Fix | Delete
# RFC 1869 requires a space between ehlo keyword and parameters.
[442] Fix | Delete
# It's actually stricter, in that only spaces are allowed between
[443] Fix | Delete
# parameters, but were not going to check for that here. Note
[444] Fix | Delete
# that the space isn't present if there are no parameters.
[445] Fix | Delete
m = re.match(r'(?P<feature>[A-Za-z0-9][A-Za-z0-9\-]*) ?', each)
[446] Fix | Delete
if m:
[447] Fix | Delete
feature = m.group("feature").lower()
[448] Fix | Delete
params = m.string[m.end("feature"):].strip()
[449] Fix | Delete
if feature == "auth":
[450] Fix | Delete
self.esmtp_features[feature] = self.esmtp_features.get(feature, "") \
[451] Fix | Delete
+ " " + params
[452] Fix | Delete
else:
[453] Fix | Delete
self.esmtp_features[feature] = params
[454] Fix | Delete
return (code, msg)
[455] Fix | Delete
[456] Fix | Delete
def has_extn(self, opt):
[457] Fix | Delete
"""Does the server support a given SMTP service extension?"""
[458] Fix | Delete
return opt.lower() in self.esmtp_features
[459] Fix | Delete
[460] Fix | Delete
def help(self, args=''):
[461] Fix | Delete
"""SMTP 'help' command.
[462] Fix | Delete
Returns help text from server."""
[463] Fix | Delete
self.putcmd("help", args)
[464] Fix | Delete
return self.getreply()[1]
[465] Fix | Delete
[466] Fix | Delete
def rset(self):
[467] Fix | Delete
"""SMTP 'rset' command -- resets session."""
[468] Fix | Delete
return self.docmd("rset")
[469] Fix | Delete
[470] Fix | Delete
def noop(self):
[471] Fix | Delete
"""SMTP 'noop' command -- doesn't do anything :>"""
[472] Fix | Delete
return self.docmd("noop")
[473] Fix | Delete
[474] Fix | Delete
def mail(self, sender, options=[]):
[475] Fix | Delete
"""SMTP 'mail' command -- begins mail xfer session."""
[476] Fix | Delete
optionlist = ''
[477] Fix | Delete
if options and self.does_esmtp:
[478] Fix | Delete
optionlist = ' ' + ' '.join(options)
[479] Fix | Delete
self.putcmd("mail", "FROM:%s%s" % (quoteaddr(sender), optionlist))
[480] Fix | Delete
return self.getreply()
[481] Fix | Delete
[482] Fix | Delete
def rcpt(self, recip, options=[]):
[483] Fix | Delete
"""SMTP 'rcpt' command -- indicates 1 recipient for this mail."""
[484] Fix | Delete
optionlist = ''
[485] Fix | Delete
if options and self.does_esmtp:
[486] Fix | Delete
optionlist = ' ' + ' '.join(options)
[487] Fix | Delete
self.putcmd("rcpt", "TO:%s%s" % (quoteaddr(recip), optionlist))
[488] Fix | Delete
return self.getreply()
[489] Fix | Delete
[490] Fix | Delete
def data(self, msg):
[491] Fix | Delete
"""SMTP 'DATA' command -- sends message data to server.
[492] Fix | Delete
[493] Fix | Delete
Automatically quotes lines beginning with a period per rfc821.
[494] Fix | Delete
Raises SMTPDataError if there is an unexpected reply to the
[495] Fix | Delete
DATA command; the return value from this method is the final
[496] Fix | Delete
response code received when the all data is sent.
[497] Fix | Delete
"""
[498] Fix | Delete
self.putcmd("data")
[499] Fix | Delete
12
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function