Add mmassive e-mail update for performance by using message set STORE command
[imap-mark-seen] / mail_iterator.py
CommitLineData
87758662 1'''
7c7f439f 2imap-mark-seen.py - Tool to mark all e-mails as seen
87758662
PD
3
4Copyright (c) 2012 Intra2net AG
5Author: Plamen Dimitrov and Thomas Jarosch
6'''
7
8import sys
9import imaplib, socket
10import re
11import logging
12
13MAILBOX_RESP = re.compile(r'\((?P<flags>.*?)\) "(?P<delimiter>.*)" (?P<name>.*)')
14
15#imaplib.Debug = 4
16
17class MailIterator:
18 """This class communicates with the e-mail server."""
19
20 # class attributes
21 # IMAP4_SSL for connection with an IMAP server
22 mail_con = None
23 # list of tuples (uidvalidity, mailboxname) for the retrieved mailboxes
24 mailboxes = None
25 # logged in status
26 logged_in = None
27
28 def __init__(self, server, username, password):
29 """Creates a connection and a user session."""
30
31 # connect to server
32 try:
33 self.mail_con = imaplib.IMAP4(server)
34 logging.info("Connected to %s", server)
35 except socket.error as ex:
36 logging.error("Could not connect to host: %s", ex)
37 sys.exit()
38
39 # log in
40 try:
41 self.mail_con.login(username, password)
42 self.logged_in = True
43 logging.info("Logged in as %s.", username)
44 except self.mail_con.error as ex:
45 self.logged_in = False
46 logging.error("Could not log in as user %s: %s", username, ex)
47 sys.exit()
48
49 # list mailboxes
50 try:
51 _result, mailboxes = self.mail_con.list()
52 except self.mail_con.error as ex:
53 logging.warning("Could not retrieve mailboxes for user %s: %s", username, ex)
54 self.mailboxes = []
55 for mailbox in mailboxes:
56 mailbox = MAILBOX_RESP.match(mailbox.decode('iso-8859-1')).groups()
57 self.mailboxes.append(mailbox)
58 self.mailboxes = sorted(self.mailboxes, key=lambda box: box[2], reverse=True)
59
60 return
61
62 def __del__(self):
63 """Closes the connection and the user session."""
64
65 if(self.logged_in):
66 self.mail_con.close()
67 self.mail_con.logout()
68
69 def __iter__(self):
70 """Iterates through all mailboxes, returns (children,delimiter,name)."""
71
72 for mailbox in self.mailboxes:
73 logging.debug("Checking mailbox %s", mailbox[2])
74 # select mailbox if writable
75 try:
76 self.mail_con.select(mailbox[2])
77 logging.info("Processing mailbox %s", mailbox[2])
78 except self.mail_con.readonly:
9d328275 79 logging.warning("Mailbox %s is not writable and therefore skipped", mailbox[2])
87758662
PD
80 continue
81 yield mailbox
82
83 def fetch_messages(self):
84 """Fetches the messages from the current mailbox, return list of uids."""
85
86 try:
87 # Work around unsolicited server responses in imaplib by clearing them
88 self.mail_con.response('SEARCH')
89 _result, data = self.mail_con.uid('search', None, "ALL")
90 except (self.mail_con.error):
9d328275 91 raise UserWarning("Could not fetch messages")
87758662
PD
92 mailid_list = data[0].split()
93 return mailid_list
94
9d328275
PD
95 def set_seen_messages(self, mid_range):
96 """Sets the \\Seen flag for all messages with the respective mids."""
87758662
PD
97
98 try:
99 # Work around unsolicited server responses in imaplib by clearing them
100 self.mail_con.response('STORE')
9d328275
PD
101 _result, data = self.mail_con.uid('STORE', mid_range, '+FLAGS', "(\Seen)")
102 logging.info("New flags for messages %s are %s", mid_range, data)
103 except (self.mail_con.error) as ex:
104 raise UserWarning("Could not set the flags for some messages: %s", ex)
87758662 105 self.mail_con.expunge()