moved build_search_query to Messages, refactored to use a class attribute of IMAP_ATTRIBUTE_LOOKUP, so that the vendors package can overwrite and add entries to it for, for example, Gmail's IMAP extensions. added X-GM-RAW to GmailMessages' copy of the lookup to make partial subject searches work.
This commit is contained in:
BIN
imbox/.DS_Store
vendored
Normal file
BIN
imbox/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -28,14 +28,16 @@ class Imbox:
|
|||||||
self.vendor = vendor or hostname_vendorname_dict.get(self.hostname)
|
self.vendor = vendor or hostname_vendorname_dict.get(self.hostname)
|
||||||
|
|
||||||
if self.vendor is not None:
|
if self.vendor is not None:
|
||||||
self.authentication_error_message = name_authentication_string_dict.get(self.vendor)
|
self.authentication_error_message = name_authentication_string_dict.get(
|
||||||
|
self.vendor)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.connection = self.server.connect(username, password)
|
self.connection = self.server.connect(username, password)
|
||||||
except imaplib.IMAP4.error as e:
|
except imaplib.IMAP4.error as e:
|
||||||
if self.authentication_error_message is None:
|
if self.authentication_error_message is None:
|
||||||
raise
|
raise
|
||||||
raise imaplib.IMAP4.error(self.authentication_error_message + '\n' + str(e))
|
raise imaplib.IMAP4.error(
|
||||||
|
self.authentication_error_message + '\n' + str(e))
|
||||||
|
|
||||||
logger.info("Connected to IMAP Server with user {username} on {hostname}{ssl}".format(
|
logger.info("Connected to IMAP Server with user {username} on {hostname}{ssl}".format(
|
||||||
hostname=hostname, username=username, ssl=(" over SSL" if ssl or starttls else "")))
|
hostname=hostname, username=username, ssl=(" over SSL" if ssl or starttls else "")))
|
||||||
@@ -61,15 +63,18 @@ class Imbox:
|
|||||||
self.connection.uid('STORE', uid, '+FLAGS', '(\\Flagged)')
|
self.connection.uid('STORE', uid, '+FLAGS', '(\\Flagged)')
|
||||||
|
|
||||||
def delete(self, uid):
|
def delete(self, uid):
|
||||||
logger.info("Mark UID {} with \\Deleted FLAG and expunge.".format(int(uid)))
|
logger.info(
|
||||||
|
"Mark UID {} with \\Deleted FLAG and expunge.".format(int(uid)))
|
||||||
self.connection.expunge()
|
self.connection.expunge()
|
||||||
|
|
||||||
def copy(self, uid, destination_folder):
|
def copy(self, uid, destination_folder):
|
||||||
logger.info("Copy UID {} to {} folder".format(int(uid), str(destination_folder)))
|
logger.info("Copy UID {} to {} folder".format(
|
||||||
|
int(uid), str(destination_folder)))
|
||||||
return self.connection.uid('COPY', uid, destination_folder)
|
return self.connection.uid('COPY', uid, destination_folder)
|
||||||
|
|
||||||
def move(self, uid, destination_folder):
|
def move(self, uid, destination_folder):
|
||||||
logger.info("Move UID {} to {} folder".format(int(uid), str(destination_folder)))
|
logger.info("Move UID {} to {} folder".format(
|
||||||
|
int(uid), str(destination_folder)))
|
||||||
if self.copy(uid, destination_folder):
|
if self.copy(uid, destination_folder):
|
||||||
self.delete(uid)
|
self.delete(uid)
|
||||||
|
|
||||||
@@ -82,7 +87,8 @@ class Imbox:
|
|||||||
messages_class = GmailMessages
|
messages_class = GmailMessages
|
||||||
|
|
||||||
if folder:
|
if folder:
|
||||||
self.connection.select(messages_class.folder_lookup.get((folder.lower())) or folder)
|
self.connection.select(
|
||||||
|
messages_class.FOLDER_LOOKUP.get((folder.lower())) or folder)
|
||||||
msg = " from folder '{}'".format(folder)
|
msg = " from folder '{}'".format(folder)
|
||||||
else:
|
else:
|
||||||
msg = " from inbox"
|
msg = " from inbox"
|
||||||
|
|||||||
@@ -1,14 +1,26 @@
|
|||||||
from imbox.parser import fetch_email_by_uid
|
import datetime
|
||||||
from imbox.query import build_search_query
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from imbox.parser import fetch_email_by_uid
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Messages:
|
class Messages:
|
||||||
|
|
||||||
folder_lookup = {}
|
IMAP_ATTRIBUTE_LOOKUP = {
|
||||||
|
'unread': '(UNSEEN)',
|
||||||
|
'unflagged': '(UNFLAGGED)',
|
||||||
|
'sent_from': '(FROM "{}")',
|
||||||
|
'sent_to': '(TO "{}")',
|
||||||
|
'date__gt': '(SINCE "{}")',
|
||||||
|
'date__lt': '(BEFORE "{}")',
|
||||||
|
'date__on': '(ON "{}")',
|
||||||
|
'subject': '(SUBJECT "{}")',
|
||||||
|
}
|
||||||
|
|
||||||
|
FOLDER_LOOKUP = {}
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
connection,
|
connection,
|
||||||
@@ -28,12 +40,25 @@ class Messages:
|
|||||||
parser_policy=self.parser_policy)
|
parser_policy=self.parser_policy)
|
||||||
|
|
||||||
def _query_uids(self, **kwargs):
|
def _query_uids(self, **kwargs):
|
||||||
query_ = build_search_query(**kwargs)
|
query_ = self._build_search_query(**kwargs)
|
||||||
message, data = self.connection.uid('search', None, query_)
|
_, data = self.connection.uid('search', None, query_)
|
||||||
if data[0] is None:
|
if data[0] is None:
|
||||||
return []
|
return []
|
||||||
return data[0].split()
|
return data[0].split()
|
||||||
|
|
||||||
|
def _build_search_query(self, **kwargs):
|
||||||
|
query = []
|
||||||
|
for name, value in kwargs.items():
|
||||||
|
if value is not None:
|
||||||
|
if isinstance(value, datetime.date):
|
||||||
|
value = value.strftime('%d-%b-%Y')
|
||||||
|
query.append(self.IMAP_ATTRIBUTE_LOOKUP[name].format(value))
|
||||||
|
|
||||||
|
if query:
|
||||||
|
return " ".join(query)
|
||||||
|
|
||||||
|
return "(ALL)"
|
||||||
|
|
||||||
def _fetch_email_list(self):
|
def _fetch_email_list(self):
|
||||||
for uid in self._uid_list:
|
for uid in self._uid_list:
|
||||||
yield uid, self._fetch_email(uid)
|
yield uid, self._fetch_email(uid)
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
import datetime
|
|
||||||
import logging
|
|
||||||
# TODO - Validate query arguments
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def format_date(date):
|
|
||||||
if isinstance(date, datetime.date):
|
|
||||||
return date.strftime('%d-%b-%Y')
|
|
||||||
return date
|
|
||||||
|
|
||||||
|
|
||||||
def build_search_query(**kwargs):
|
|
||||||
|
|
||||||
# Parse keyword arguments
|
|
||||||
unread = kwargs.get('unread', False)
|
|
||||||
unflagged = kwargs.get('unflagged', False)
|
|
||||||
flagged = kwargs.get('flagged', False)
|
|
||||||
sent_from = kwargs.get('sent_from', False)
|
|
||||||
sent_to = kwargs.get('sent_to', False)
|
|
||||||
date__gt = kwargs.get('date__gt', False)
|
|
||||||
date__lt = kwargs.get('date__lt', False)
|
|
||||||
date__on = kwargs.get('date__on', False)
|
|
||||||
subject = kwargs.get('subject')
|
|
||||||
|
|
||||||
query = []
|
|
||||||
|
|
||||||
if unread:
|
|
||||||
query.append("(UNSEEN)")
|
|
||||||
|
|
||||||
if unflagged:
|
|
||||||
query.append("(UNFLAGGED)")
|
|
||||||
|
|
||||||
if flagged:
|
|
||||||
query.append("(FLAGGED)")
|
|
||||||
|
|
||||||
if sent_from:
|
|
||||||
query.append('(FROM "%s")' % sent_from)
|
|
||||||
|
|
||||||
if sent_to:
|
|
||||||
query.append('(TO "%s")' % sent_to)
|
|
||||||
|
|
||||||
if date__gt:
|
|
||||||
query.append('(SINCE "%s")' % format_date(date__gt))
|
|
||||||
|
|
||||||
if date__lt:
|
|
||||||
query.append('(BEFORE "%s")' % format_date(date__lt))
|
|
||||||
|
|
||||||
if date__on:
|
|
||||||
query.append('(ON "%s")' % format_date(date__on))
|
|
||||||
|
|
||||||
if subject is not None:
|
|
||||||
query.append('(SUBJECT "%s")' % subject)
|
|
||||||
|
|
||||||
if query:
|
|
||||||
logger.debug("IMAP query: {}".format(" ".join(query)))
|
|
||||||
return " ".join(query)
|
|
||||||
|
|
||||||
logger.debug("IMAP query: {}".format("(ALL)"))
|
|
||||||
return "(ALL)"
|
|
||||||
5
imbox/vendors/gmail.py
vendored
5
imbox/vendors/gmail.py
vendored
@@ -6,7 +6,7 @@ class GmailMessages(Messages):
|
|||||||
'https://myaccount.google.com/apppasswords')
|
'https://myaccount.google.com/apppasswords')
|
||||||
hostname = 'imap.gmail.com'
|
hostname = 'imap.gmail.com'
|
||||||
name = 'gmail'
|
name = 'gmail'
|
||||||
folder_lookup = {
|
FOLDER_LOOKUP = {
|
||||||
|
|
||||||
'all_mail': '"[Gmail]/All Mail"',
|
'all_mail': '"[Gmail]/All Mail"',
|
||||||
'all': '"[Gmail]/All Mail"',
|
'all': '"[Gmail]/All Mail"',
|
||||||
@@ -19,11 +19,12 @@ class GmailMessages(Messages):
|
|||||||
'spam': '"[Gmail]/Spam"',
|
'spam': '"[Gmail]/Spam"',
|
||||||
'starred': '"[Gmail]/Starred"',
|
'starred': '"[Gmail]/Starred"',
|
||||||
'trash': '"[Gmail]/Trash"',
|
'trash': '"[Gmail]/Trash"',
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
connection,
|
connection,
|
||||||
parser_policy,
|
parser_policy,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
|
|
||||||
|
self.IMAP_ATTRIBUTE_LOOKUP['subject'] = '(X-GM-RAW "{}")'
|
||||||
super().__init__(connection, parser_policy, **kwargs)
|
super().__init__(connection, parser_policy, **kwargs)
|
||||||
|
|||||||
Reference in New Issue
Block a user