Python try / except issue with SMTPLib
Following on from the support from @AndreySobolev I got the following simple code working fine:
import smtplib, socket
try:
mylib = smtplib.SMTP("127.0.0.1", 25)
except socket.error as e:
print "could not connect"
So I then returned to my smtplib_client.py, and block commented out most of the "try" section. This worked fine... so bit by bit, I reinstated more and more of the try section.... and each and every time it worked fine. The final version is below. Other than what I do in my except socket.error
handler, I can't say that I am aware of anything I have changed - other than I also added a server = None
so as to stop the finally
section working. Oh, and I also had to add "socket" to my list of imports. Without this I could understand the except not handling correctly - but I don't understand why it wasn't firing at all, or even generating a "not defined" error.... Odd!
Working code:
def runClient(configName = 'default', testFile = './test.xml'):
cliCfg = getClientConfig(configName)
print cliCfg.find('logfile').text
# startLogger(cliCfg.find('logfile').text)
clientCert = cliCfg.find('cert').text
clientKey = cliCfg.find('key').text
serverHost = cliCfg.find('serverhost').text
serverPort = int(cliCfg.find('serverport').text)
myMail = MailMessageHandler()
msgSrc = myMail.readMessageSource(testFile)
allMsgs = myMail.processMessages(msgSrc)
inx = 1
for msg in allMsgs:
validMsg = True
requiredKeys = ('ehlo', 'sndr', 'rcpt', 'body')
for msgItems in requiredKeys:
if len(msg[msgItems]) == 0:
validMsg = False
if validMsg:
try:
server = None
server = smtplib.SMTP(serverHost, serverPort)
server.ehlo(msg['ehlo'])
thisSender = msg['sndr']
thisRecipient = msg['rcpt']
thisMessage = MIMEText(msg['body'])
thisMessage['To'] = email.utils.formataddr(('', thisRecipient))
thisMessage['From'] = email.utils.formataddr(('', thisSender))
thisMessage['Subject'] = msg['subject']
thisMessage['Message-id'] = email.utils.make_msgid()
now = datetime.now()
day = now.strftime('%a')
date = now.strftime('%d %b %Y %X')
thisMessage['Date'] = day + ', ' + date + ' -0000'
if msg['tls'].lower() == 'true':
server.starttls('certs/client/client.key', 'certs/client/client.crt')
logging.info ("Message: " + thisMessage['Message-id'] + " to be sent over TLS")
server.sendmail(thisSender, thisRecipient.split(","), thisMessage.as_string())
logging.info ("Message: " + thisMessage['Message-id'] + " sent successfully to " + serverHost + ":" + cliCfg.find('serverport').text)
logging.info ("Message: " + thisMessage['Message-id'] + " had sender: " + thisMessage['From'])
logging.info ("Message: " + thisMessage['Message-id'] + " had recipient(s): " + thisMessage['To'])
except socket.error as e:
logging.error ("Could not connect to " + serverHost + ":" + cliCfg.find('serverport').text + " - is it listening / up?")
except:
print "Unknown error:", sys.exc_info()[0]
finally:
if server != None:
server.quit()
else:
print "Improperly formatted source mail - please check"
Baffled, yet relieved! Thanks Andrey!
Steve Hall
Jack of many trades, master of not so many! QTP specialist, HP certified. Can turn my hand to most forms of scripting though, especially for automated testing - QTP, TestComplete, a bit of Selenium etc etc. Just recently started to learn a bit of Ruby, Rails, and all the fun that goes with that. It's a steep curve, but I've brought my mountaineering kit with me :).... Or I was, until that got put on hold, and now I'm onto Python, and Twisted. What will it be next week? Stay tuned... :)
Updated on June 22, 2022Comments
-
Steve Hall almost 2 years
I've written a simple SMTP client using Python's SMTPLib. Just trying to add some error handling - specifically in this instance, when the target server to connect to is unavailable (eg, wrong IP specified!)
Currently, the traceback looks like this:
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "smtplib_client.py", line 91, in runClient try: File "/usr/local/lib/python2.7/smtplib.py", line 251, in __init__ (code, msg) = self.connect(host, port) File "/usr/local/lib/python2.7/smtplib.py", line 311, in connect self.sock = self._get_socket(host, port, self.timeout) File "/usr/local/lib/python2.7/smtplib.py", line 286, in _get_socket return socket.create_connection((host, port), timeout) File "/usr/local/lib/python2.7/socket.py", line 571, in create_connection raise err socket.error: [Errno 111] Connection refused
So clearly, it's "create_connection" in socket.py going bang. This has it's own try / except block:
for res in getaddrinfo(host, port, 0, SOCK_STREAM): af, socktype, proto, canonname, sa = res sock = None try: sock = socket(af, socktype, proto) if timeout is not _GLOBAL_DEFAULT_TIMEOUT: sock.settimeout(timeout) if source_address: sock.bind(source_address) sock.connect(sa) return sock except error as _: err = _ if sock is not None: sock.close() if err is not None: raise err else: raise error("getaddrinfo returns an empty list")
My runClient() function looks like:
def runClient(configName = 'default', testFile = './test.xml'): cliCfg = getClientConfig(configName) print cliCfg.find('logfile').text # startLogger(cliCfg.find('logfile').text) clientCert = cliCfg.find('cert').text clientKey = cliCfg.find('key').text serverHost = cliCfg.find('serverhost').text serverPort = int(cliCfg.find('serverport').text) myMail = MailMessageHandler() msgSrc = myMail.readMessageSource(testFile) allMsgs = myMail.processMessages(msgSrc) inx = 1 for msg in allMsgs: validMsg = True requiredKeys = ('ehlo', 'sndr', 'rcpt', 'body') for msgItems in requiredKeys: if len(msg[msgItems]) == 0: validMsg = False if validMsg: try: server = smtplib.SMTP(serverHost, serverPort) server.ehlo(msg['ehlo']) thisSender = msg['sndr'] thisRecipient = msg['rcpt'] thisMessage = MIMEText(msg['body']) thisMessage['To'] = email.utils.formataddr(('', thisRecipient)) thisMessage['From'] = email.utils.formataddr(('', thisSender)) thisMessage['Subject'] = msg['subject'] thisMessage['Message-id'] = email.utils.make_msgid() now = datetime.now() day = now.strftime('%a') date = now.strftime('%d %b %Y %X') thisMessage['Date'] = day + ', ' + date + ' -0000' if msg['tls'].lower() == 'true': server.starttls('certs/client/client.key', 'certs/client/client.crt') logging.info ("Message: " + thisMessage['Message-id'] + " to be sent over TLS") server.sendmail(thisSender, thisRecipient.split(","), thisMessage.as_string()) logging.info ("Message: " + thisMessage['Message-id'] + " sent successfully to " + serverHost + ":" + cliCfg.find('serverport').text) logging.info ("Message: " + thisMessage['Message-id'] + " had sender: " + thisMessage['From']) logging.info ("Message: " + thisMessage['Message-id'] + " had recipient(s): " + thisMessage['To']) except socket.error as e: print "Could not connect to server - is it down? ({0}): {1}".format(e.strerrror) except: print "Unknown error:", sys.exc_info()[0] finally: server.quit() else: print "Improperly formatted source mail - please check"
What I don't get is - the traceback shows the call to
raise err
. So clearlyerr
is not None, and so it must be set as part ofexcept error as _:
.... So the error is initially handled, but as part of the handler, a copy is created (err
) - which is subsequently raised outside of the try/except block - so is unhandled. This unhandled error should then get "passed back up" the call stack (get_socket
has no try/except block, nor doconnect
or__init__
- so outside of the try/except block for the originalerror
increate_connection
, the copy of the error,err
should surely then "cascade" back to the try/except block in my runClient function?