Commit | Line | Data |
---|---|---|
87758662 | 1 | ''' |
1d595a61 | 2 | The module contains the MailIterator class. |
87758662 PD |
3 | |
4 | Copyright (c) 2012 Intra2net AG | |
9bfaa115 | 5 | Author: Plamen Dimitrov |
6a1e092b PD |
6 | |
7 | This program is free software: you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation, either version 3 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
87758662 PD |
16 | ''' |
17 | ||
18 | import sys | |
19 | import imaplib, socket | |
20 | import re | |
21 | import logging | |
22 | ||
23 | MAILBOX_RESP = re.compile(r'\((?P<flags>.*?)\) "(?P<delimiter>.*)" (?P<name>.*)') | |
24 | ||
25 | #imaplib.Debug = 4 | |
26 | ||
27 | class MailIterator: | |
25ef1a0c | 28 | """This class communicates with the IMAP server.""" |
87758662 PD |
29 | |
30 | # class attributes | |
31 | # IMAP4_SSL for connection with an IMAP server | |
32 | mail_con = None | |
33 | # list of tuples (uidvalidity, mailboxname) for the retrieved mailboxes | |
34 | mailboxes = None | |
35 | # logged in status | |
36 | logged_in = None | |
37 | ||
38 | def __init__(self, server, username, password): | |
39 | """Creates a connection and a user session.""" | |
40 | ||
41 | # connect to server | |
42 | try: | |
25ef1a0c | 43 | self.mail_con = imaplib.IMAP4_SSL(server) |
87758662 PD |
44 | logging.info("Connected to %s", server) |
45 | except socket.error as ex: | |
46 | logging.error("Could not connect to host: %s", ex) | |
47 | sys.exit() | |
48 | ||
49 | # log in | |
50 | try: | |
51 | self.mail_con.login(username, password) | |
52 | self.logged_in = True | |
53 | logging.info("Logged in as %s.", username) | |
54 | except self.mail_con.error as ex: | |
55 | self.logged_in = False | |
56 | logging.error("Could not log in as user %s: %s", username, ex) | |
57 | sys.exit() | |
58 | ||
59 | # list mailboxes | |
60 | try: | |
61 | _result, mailboxes = self.mail_con.list() | |
62 | except self.mail_con.error as ex: | |
63 | logging.warning("Could not retrieve mailboxes for user %s: %s", username, ex) | |
64 | self.mailboxes = [] | |
65 | for mailbox in mailboxes: | |
66 | mailbox = MAILBOX_RESP.match(mailbox.decode('iso-8859-1')).groups() | |
67 | self.mailboxes.append(mailbox) | |
68 | self.mailboxes = sorted(self.mailboxes, key=lambda box: box[2], reverse=True) | |
69 | ||
70 | return | |
71 | ||
72 | def __del__(self): | |
73 | """Closes the connection and the user session.""" | |
74 | ||
75 | if(self.logged_in): | |
76 | self.mail_con.close() | |
77 | self.mail_con.logout() | |
78 | ||
79 | def __iter__(self): | |
80 | """Iterates through all mailboxes, returns (children,delimiter,name).""" | |
81 | ||
82 | for mailbox in self.mailboxes: | |
83 | logging.debug("Checking mailbox %s", mailbox[2]) | |
84 | # select mailbox if writable | |
85 | try: | |
86 | self.mail_con.select(mailbox[2]) | |
87 | logging.info("Processing mailbox %s", mailbox[2]) | |
88 | except self.mail_con.readonly: | |
9d328275 | 89 | logging.warning("Mailbox %s is not writable and therefore skipped", mailbox[2]) |
87758662 PD |
90 | continue |
91 | yield mailbox | |
92 | ||
93 | def fetch_messages(self): | |
94 | """Fetches the messages from the current mailbox, return list of uids.""" | |
95 | ||
96 | try: | |
97 | # Work around unsolicited server responses in imaplib by clearing them | |
98 | self.mail_con.response('SEARCH') | |
99 | _result, data = self.mail_con.uid('search', None, "ALL") | |
100 | except (self.mail_con.error): | |
9d328275 | 101 | raise UserWarning("Could not fetch messages") |
87758662 PD |
102 | mailid_list = data[0].split() |
103 | return mailid_list | |
104 | ||
9d328275 PD |
105 | def set_seen_messages(self, mid_range): |
106 | """Sets the \\Seen flag for all messages with the respective mids.""" | |
9bfaa115 | 107 | |
87758662 PD |
108 | try: |
109 | # Work around unsolicited server responses in imaplib by clearing them | |
110 | self.mail_con.response('STORE') | |
9d328275 PD |
111 | _result, data = self.mail_con.uid('STORE', mid_range, '+FLAGS', "(\Seen)") |
112 | logging.info("New flags for messages %s are %s", mid_range, data) | |
113 | except (self.mail_con.error) as ex: | |
114 | raise UserWarning("Could not set the flags for some messages: %s", ex) | |
87758662 | 115 | self.mail_con.expunge() |