title: Python try / except issue with SMTPLib
body: <p>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!)</p>
  
  <p>Currently, the traceback looks like this:</p>
  
  <pre><code>Traceback (most recent call last):
    File "&lt;stdin&gt;", line 1, in &lt;module&gt;
    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
  </code></pre>
  
  <p>So clearly, it's "create_connection" in socket.py going bang. This has it's own try / except block:</p>
  
  <pre><code>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")
  </code></pre>
  
  <p>My runClient() function looks like:</p>
  
  <pre><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 = 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"
  </code></pre>
  
  <p>What I don't get is - the traceback shows the call to <code>raise err</code>. So clearly <code>err</code> is not None, and so it must be set as part of <code>except error as _:</code>.... So the error is initially handled, but as part of the handler, a copy is created (<code>err</code>) - 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 (<code>get_socket</code> has no try/except block, nor do <code>connect</code> or <code>__init__</code> - so outside of the try/except block for the original <code>error</code> in <code>create_connection</code>, the copy of the error, <code>err</code> should surely then  "cascade" back to the try/except block in my runClient function?</p>