diff --git a/.gitignore b/.gitignore index 96778bd..ea28487 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,9 @@ tmtags ## PROJECT::GENERAL *.pyc +build/ +dist/ +gmail.egg-info/ ## PROJECT::SPECIFIC *.rdb diff --git a/README.md b/README.md index aae4856..b27936a 100644 --- a/README.md +++ b/README.md @@ -8,15 +8,16 @@ __This library is still under development, so please forgive some of the rough e Heavily inspired by [Kriss "nu7hatch" Kowalik's GMail for Ruby library](https://github.com/nu7hatch/gmail) -## Author +## Contributors -* [Charlie Guo](https://github.com/charlierguo) +* [Charlie Guo](https://github.com/charlierguo) - Author of the original python2 package +* [Reuben Castelino](https://github.com/projectdelphai) - Edited by me to work with python3 ## Installation -For now, installation is manual (`pip` support not yet implemented) and the only requirement is to use Python 2 (2.7+ to be precise): +For now, installation is manual (`pip` support not yet implemented) and the only requirement is to use Python 3 - git clone git://github.com/charlierguo/gmail.git + git clone git://github.com/projectdelphai/gmail.git ## Features diff --git a/gmail/gmail.py b/gmail/gmail.py index 7fb09e1..4c2de01 100644 --- a/gmail/gmail.py +++ b/gmail/gmail.py @@ -1,9 +1,9 @@ import re import imaplib -from mailbox import Mailbox -from utf import encode as encode_utf7, decode as decode_utf7 -from exceptions import * +from .mailbox import Mailbox +from .utf import encode as encode_utf7, decode as decode_utf7 +from .exceptions import * class Gmail(): # GMail IMAP defaults @@ -53,7 +53,7 @@ def fetch_mailboxes(self): response, mailbox_list = self.imap.list() if response == 'OK': for mailbox in mailbox_list: - mailbox_name = mailbox.split('"/"')[-1].replace('"', '').strip() + mailbox_name = mailbox.decode().split('"/"')[-1].replace('"', '').strip() mailbox = Mailbox(self) mailbox.external_name = mailbox_name self.mailboxes[mailbox_name] = mailbox @@ -147,9 +147,9 @@ def copy(self, uid, to_mailbox, from_mailbox=None): self.imap.uid('COPY', uid, to_mailbox) def fetch_multiple_messages(self, messages): - fetch_str = ','.join(messages.keys()) + fetch_str = ','.join(list(messages.keys())) response, results = self.imap.uid('FETCH', fetch_str, '(BODY.PEEK[] FLAGS X-GM-THRID X-GM-MSGID X-GM-LABELS)') - for index in xrange(len(results) - 1): + for index in range(len(results) - 1): raw_message = results[index] if re.search(r'UID (\d+)', raw_message[0]): uid = re.search(r'UID (\d+)', raw_message[0]).groups(1)[0] @@ -159,7 +159,7 @@ def fetch_multiple_messages(self, messages): def labels(self, require_unicode=False): - keys = self.mailboxes.keys() + keys = list(self.mailboxes.keys()) if require_unicode: keys = [decode_utf7(key) for key in keys] return keys diff --git a/gmail/mailbox.py b/gmail/mailbox.py index 0368034..aac7f7c 100644 --- a/gmail/mailbox.py +++ b/gmail/mailbox.py @@ -1,5 +1,5 @@ -from message import Message -from utf import encode as encode_utf7, decode as decode_utf7 +from .message import Message +from .utf import encode as encode_utf7, decode as decode_utf7 class Mailbox(): @@ -60,7 +60,7 @@ def mail(self, prefetch=False, **kwargs): # print search response, data = self.gmail.imap.uid('SEARCH', *search) if response == 'OK': - uids = filter(None, data[0].split(' ')) # filter out empty strings + uids = [_f for _f in data[0].decode().split(' ') if _f] # filter out empty strings for uid in uids: if not self.messages.get(uid): @@ -91,7 +91,7 @@ def threads(self, prefetch=False, **kwargs): if prefetch: fetch_str = ','.join(uids) response, results = self.gmail.imap.uid('FETCH', fetch_str, '(BODY.PEEK[] FLAGS X-GM-THRID X-GM-MSGID X-GM-LABELS)') - for index in xrange(len(results) - 1): + for index in range(len(results) - 1): raw_message = results[index] if re.search(r'UID (\d+)', raw_message[0]): uid = re.search(r'UID (\d+)', raw_message[0]).groups(1)[0] diff --git a/gmail/message.py b/gmail/message.py index 9813ce4..a0dacb9 100644 --- a/gmail/message.py +++ b/gmail/message.py @@ -113,7 +113,7 @@ def archive(self): def parse_headers(self, message): hdrs = {} - for hdr in message.keys(): + for hdr in list(message.keys()): hdrs[hdr] = message[hdr] return hdrs @@ -124,20 +124,23 @@ def parse_flags(self, headers): def parse_labels(self, headers): if re.search(r'X-GM-LABELS \(([^\)]+)\)', headers): labels = re.search(r'X-GM-LABELS \(([^\)]+)\)', headers).groups(1)[0].split(' ') - return map(lambda l: l.replace('"', '').decode("string_escape"), labels) + return [l.replace('"', '').encode().decode("unicode_escape") for l in labels] else: return list() def parse_subject(self, encoded_subject): dh = decode_header(encoded_subject) - default_charset = 'ASCII' - return ''.join([ unicode(t[0], t[1] or default_charset) for t in dh ]) + + # dh is a list that has (str, None) and (bytes, encoding) objects + return ''.join( + value.decode(encoding) if encoding else value + for value, encoding in dh) def parse(self, raw_message): - raw_headers = raw_message[0] + raw_headers = raw_message[0].decode() raw_email = raw_message[1] - self.message = email.message_from_string(raw_email) + self.message = email.message_from_string(raw_email.decode()) self.headers = self.parse_headers(self.message) self.to = self.message['to'] @@ -157,7 +160,7 @@ def parse(self, raw_message): self.sent_at = datetime.datetime.fromtimestamp(time.mktime(email.utils.parsedate_tz(self.message['date'])[:9])) - self.flags = self.parse_flags(raw_headers) + self.flags = self.parse_flags(raw_headers.encode()) self.labels = self.parse_labels(raw_headers) @@ -170,7 +173,7 @@ def parse(self, raw_message): # Parse attachments into attachment objects array for this message self.attachments = [ Attachment(attachment) for attachment in self.message._payload - if not isinstance(attachment, basestring) and attachment.get('Content-Disposition') is not None + if not isinstance(attachment, str) and attachment.get('Content-Disposition') is not None ] @@ -210,7 +213,7 @@ def fetch_thread(self): self.gmail.use_mailbox(original_mailbox.name) # combine and sort sent and received messages - return sorted(dict(received_messages.items() + sent_messages.items()).values(), key=lambda m: m.sent_at) + return sorted(list(dict(list(received_messages.items()) + list(sent_messages.items())).values()), key=lambda m: m.sent_at) class Attachment: diff --git a/gmail/utf.py b/gmail/utf.py index c953e73..8efc230 100644 --- a/gmail/utf.py +++ b/gmail/utf.py @@ -22,8 +22,8 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -text_type = unicode -binary_type = str +text_type = str +binary_type = bytes PRINTABLE = set(range(0x20, 0x26)) | set(range(0x27, 0x7f)) @@ -96,4 +96,4 @@ def modified_utf7(s): def modified_deutf7(s): s_utf7 = '+' + s.replace(',', '/') + '-' # encode to latin-1: '+AP8-' => b'+AP8-', decode from utf-7 => '\xff' - return s_utf7.encode('latin-1').decode('utf-7') \ No newline at end of file + return s_utf7.encode('latin-1').decode('utf-7')