September 16, 2022
Testing IMAP IDLE/NOTIFY with python
I have to troubleshoot a buggy relationship between a mail client (thunderbird) and an IMAP server (dovecot), regarding notification. That’s when the server informs the client about new mails, as opposed to the client polling the server to get this information.
There’s this stackoverflow thread with some very useful exemple code. Unfortunately, it’s old, and python 2 only.
For the record, here’s the version I’ve used, updated to p3k, and with some slight modifications: single file, reporting exception in the main loop instead of just ignoring them with the ‘finally’ close. It’s not as clean and efficient as I would like, but it works and is not THAT dirty.
File imapidletest.py
import imaplib
import configparser
from os.path import abspath
def open_connection(verbose=False):
# Read the config file
config = configparser.ConfigParser()
config.read([abspath('settings.ini')])
# Connect to the server
hostname = config.get('server', 'hostname')
if verbose: print('Connecting to', hostname)
connection = imaplib.IMAP4_SSL(hostname)
# Login to our account
username = config.get('account', 'username')
password = config.get('account', 'password')
if verbose: print('Logging in as', username)
connection.login(username, password)
return connection
imaplib.Debug = 4
c = open_connection()
try:
c.select('INBOX', readonly=True)
c.send(b"%s IDLE\r\n"%(c._new_tag()))
print(">>> waiting for new mail...")
while True:
line = c.readline().strip();
if line.startswith(b'* BYE ') or (len(line) == 0):
print(">>> leaving...")
break
if line.endswith(b'EXISTS'):
print(">>> NEW MAIL ARRIVED!")
except Exception as e:
print("Exception:")
print(e)
finally:
try:
print(">>> closing...")
c.close()
except:
pass
c.logout()
You need a file settings.ini
like this one:
[server]
hostname: imap.xxx.com
[account]
username: mylogin
password: my_clear_password