# Is 'try / finally' the best way for me to handle (and close) this long-running IMAP4 connection?

I'm writing a script to archive email messages from one IMAP folder to another. It looks, more or less, like the following. I've obfuscated about 30 lines unrelated to this question:

import imaplib
import getpass

def main():
user = getpass.getuser() + '@mymailbox.com'
mailbox = imaplib.IMAP4_SSL('mymailbox.com', 993)
try:
except imaplib.IMAP4.error:
raise RuntimeError('Credential error.')
mailbox.select('my_mailbox')

# Here lies some 30 lines not relevant to the question, but which
# find mailbox messages, copies them to another folder, and
# sets the delete flag in 'my_mailbox'.

try:
mailbox.close()    # which also expunges the mailbox
except:
pass
mailbox.logout()


After working with my IMAP server for a while, I've discovered a fair amount of unexpected error conditions arising from its implementation of RFC 3501. No matter what, however, I always want to attempt mailbox.close() and mailbox.logout().

It sounds like a good occasion for a try / finally block, and that usage is supported by other examples. All the same, it feels unnatural to wrap some 40 lines of main() execution in a try-block:

def main():
user = getpass.getuser() + '@mymailbox.com'
mailbox = imaplib.IMAP4_SSL('mymailbox.com', 993)
try:
try:
except imaplib.IMAP4.error:
raise RuntimeError('Credential error.')
mailbox.select('my_mailbox')

# Here lies some 30 lines not relevant to the question, but which
# find mailbox messages, copy them to another folder, and
# set delete flags in 'my_mailbox'.
finally:
try:
mailbox.close()    # which also expunges the mailbox
except:
pass
mailbox.logout()


Is that a common pattern? I could also write my own context manager; perhaps that's the better way to go. What's the best practice for long-running connections like this?

Move the working logic into its own function

def process_mailbox(mailbox):
user = getpass.getuser() + '@mymailbox.com'
try:
except imaplib.IMAP4.error:
raise RuntimeError('Credential error.')
mailbox.select('my_mailbox')
#whatever else

def main():
mailbox = imaplib.IMAP4_SSL('mymailbox.com', 993)
try:
process_mailbox(mailbox)
finally:
try:
mailbox.close()    # which also expunges the mailbox
except:
pass
mailbox.logout()

• Stunningly obvious, in retrospect. Any thoughts on with vs. try / finally here? – Christopher May 6 '13 at 2:49
• @Christopher, the with gets really helpful if you need to do this a lot. If this is the only function where you do it, it wouldn't seem all that people. – Winston Ewert May 6 '13 at 2:59