Skip to content

Commit

Permalink
BaseMailBox.fetch headers_only arg fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
ikvk committed Aug 28, 2020
1 parent 47a4053 commit cef0f37
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 22 deletions.
10 changes: 6 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,12 @@ Basic
subjects = [msg.subject for msg in mailbox.fetch(AND(all=True))]
mailbox.logout()
MailBox/MailBoxUnencrypted - for create mailbox instance.
MailBox, MailBoxUnencrypted - for create mailbox instance.

MailBox.box - imaplib.IMAP4/IMAP4_SSL client instance.

MailBox.login - authentication function

MailBox.fetch - email message generator, first searches email ids by criteria, then fetch and yields emails by one:

* *criteria* = 'ALL', message search criteria, `docs <#search-criteria>`_
Expand All @@ -58,7 +60,7 @@ MailBox.fetch - email message generator, first searches email ids by criteria, t
* *miss_no_uid* = True, miss emails without uid
* *mark_seen* = True, mark emails as seen on fetch
* *reverse* = False, in order from the larger date to the smaller
* *headers_only* = False, get only email headers (without text, html, attachments) !disabled until fix bug
* *headers_only* = False, get only email headers (without text, html, attachments)

Email attributes
^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -137,7 +139,7 @@ Header H for search by headers name: str, value: str
# complex
A(OR(from_='[email protected]', text='"the text"'), NOT(OR(A(answered=False), A(new=True))), to='[email protected]')
# encoding
mailbox.fetch(A(subject='привет'), charset='utf8') # 'привет' will be encoded by MailBox._criteria_encoder
mailbox.fetch(A(subject='привет'), charset='utf8')
# python note: you can't do: A(text='two', NOT(subject='one'))
A(NOT(subject='one'), text='two') # use kwargs after logic classes (args)
Expand Down Expand Up @@ -248,7 +250,7 @@ Custom lib exceptions here: `errors.py <https://github.com/ikvk/imap_tools/blob/
Release notes
-------------

History of important changes: `release_notes.rst <https://github.com/ikvk/imap_tools/blob/master/release_notes.rst>`_
History of important changes: `release_notes.rst <https://github.com/ikvk/imap_tools/blob/master/docs/release_notes.rst>`_

Contribute
----------
Expand Down
4 changes: 4 additions & 0 deletions release_notes.rst → docs/release_notes.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
0.20.0
======
* BaseMailBox.fetch headers_only arg fixed

0.19.1
======
* Importing all from utils module removed from the default package imports
Expand Down
4 changes: 1 addition & 3 deletions docs/todo.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
check https://docs.python.org/release/3.8.1/library/email.utils.html

fix BaseMailBox.fetch headers_only

__getitem__ -> https://docs.python.org/3/library/email.compat32-message.html#email.message.Message.get_all
__getitem__ -> https://docs.python.org/3/library/email.compat32-message.html#email.message.Message.get_all ?
10 changes: 7 additions & 3 deletions imap_tools/mailbox.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import imaplib
from email.errors import StartBoundaryNotFoundDefect, MultipartInvariantViolationDefect

from .message import MailMessage, MailMessageFlags
from .folder import MailBoxFolderManager
Expand All @@ -15,6 +16,7 @@ class BaseMailBox:

email_message_class = MailMessage
folder_manager_class = MailBoxFolderManager
with_headers_only_allowed_errors = (StartBoundaryNotFoundDefect, MultipartInvariantViolationDefect)

def __init__(self):
self.folder = None # folder manager
Expand Down Expand Up @@ -56,8 +58,6 @@ def fetch(self, criteria: str or bytes = 'ALL', charset: str = 'US-ASCII', limit
:param headers_only: get only email headers (without text, html, attachments)
:return generator: MailMessage
"""
if headers_only:
raise NotImplementedError('headers_only does not work correctly and is disabled until fix, *you may help')
search_result = self.box.search(charset, self._criteria_encoder(criteria, charset))
check_command_status(search_result, MailboxSearchError)
# first element is string with email numbers through the gap
Expand All @@ -71,7 +71,11 @@ def fetch(self, criteria: str or bytes = 'ALL', charset: str = 'US-ASCII', limit
check_command_status(fetch_result, MailboxFetchError)
mail_message = self.email_message_class(fetch_result[1])
if miss_defect and mail_message.obj.defects:
continue
if headers_only:
if not all(d.__class__ in self.with_headers_only_allowed_errors for d in mail_message.obj.defects):
continue
else:
continue
if miss_no_uid and not mail_message.uid:
continue
yield mail_message
Expand Down
29 changes: 17 additions & 12 deletions tests/test_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@ def test_live(self):
none_type = type(None)
for mailbox in self.mailbox_set.values():
mailbox.folder.set(mailbox.folder_test_base)

# headers_only
# cnt_fetch_head = 0
# cnt_fetch_head_answered_and_flagged = 0
# for message in mailbox.fetch(headers_only=True):
# if {MailMessageFlags.ANSWERED, MailMessageFlags.FLAGGED}.issubset(message.flags):
# cnt_fetch_head_answered_and_flagged += 1
# cnt_fetch_head += 1
# self.assertEqual(message.text, '')
# self.assertEqual(message.html, '')
# self.assertEqual(len(message.attachments), 0)
cnt_fetch_head = 0
cnt_fetch_head_answered_and_flagged = 0
for message in mailbox.fetch(headers_only=True):
if {MailMessageFlags.ANSWERED, MailMessageFlags.FLAGGED}.issubset(message.flags):
cnt_fetch_head_answered_and_flagged += 1
cnt_fetch_head += 1
self.assertEqual(message.text, '')
self.assertEqual(message.html, '')
self.assertEqual(len(message.attachments), 0)

# types
cnt_fetch_all = 0
Expand Down Expand Up @@ -57,12 +58,16 @@ def test_live(self):
self.assertIs(type(att.filename), str)
self.assertIs(type(att.content_type), str)
self.assertIs(type(att.payload), bytes)

# counts
self.assertTrue(cnt_fetch_all_answered_and_flagged >= 1)
self.assertEqual(cnt_fetch_all, 6)
# self.assertEqual(cnt_fetch_head, cnt_fetch_all)
# self.assertTrue(cnt_fetch_head_answered_and_flagged >= 1)
# self.assertEqual(cnt_fetch_head_answered_and_flagged, cnt_fetch_all_answered_and_flagged)

self.assertTrue(cnt_fetch_head_answered_and_flagged >= 1)
self.assertEqual(cnt_fetch_head, 6)

self.assertEqual(cnt_fetch_head, cnt_fetch_all)
self.assertEqual(cnt_fetch_head_answered_and_flagged, cnt_fetch_all_answered_and_flagged)

def test_attributes(self):
msg_attr_set = {'subject', 'from_', 'to', 'cc', 'bcc', 'reply_to', 'date', 'date_str', 'text', 'html',
Expand Down

0 comments on commit cef0f37

Please sign in to comment.