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