Skip to content

Commit

Permalink
Merge pull request #48 from Jantek/master
Browse files Browse the repository at this point in the history
Could run as Docker Container
  • Loading branch information
jamesridgway authored Feb 17, 2024
2 parents 33e137e + 637428d commit e27357e
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 40 deletions.
11 changes: 11 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
__pycache__/
.coverage
.idea/
.pytest_cache/
*.egg-info
*.pyc
attachment_downloader/version.py
dist/
htmlcov/
venv/
.github
11 changes: 11 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM python:3-alpine

WORKDIR /usr/src/app

COPY . .

RUN apk add --no-cache git

RUN pip install --no-cache-dir .

CMD [ "attachment-downloader" ]
110 changes: 70 additions & 40 deletions bin/attachment-downloader
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import os
import re
import ssl
import sys
import time
from copy import copy
from optparse import OptionParser, Option

Expand Down Expand Up @@ -32,6 +33,7 @@ def build_filter_options():

def process_message(filename_template, options, message):
subject = ''
sent_to = ''
if hasattr(message, 'subject'):
subject = QuoPriEncoding.decode(message.subject)

Expand All @@ -40,20 +42,20 @@ def process_message(filename_template, options, message):
except Exception as e:
logging.exception(e)
if hasattr(message, 'date'):
logging.error("Skipping message '%s' subject '%s' because date can not be parsed '%s'", uid,
subject, message.date)
logging.error("Skipping message '%s' subject '%s' send to '%s' because date can not be parsed '%s'", uid,
subject, message.sent_to[0]['email'], message.date)
else:
logging.error("Skipping message '%s' subject '%s' because message does not have a date attribute",
uid, subject)
logging.error("Skipping message '%s' subject '%s' send to '%s' because message does not have a date attribute",
uid, subject, message.sent_to[0]['email'])
return

if options.date_after and parsed_message_date < options.date_after:
logging.warning("Skipping message '%s' subject '%s' because it is before %s", uid, subject,
logging.warning("Skipping message '%s' subject '%s' send to '%s' because it is before %s", uid, subject, message.sent_to[0]['email'],
options.date_after)
return

if options.date_before and parsed_message_date >= options.date_before:
logging.warning("Skipping message '%s' subject '%s' because it is after %s", uid, subject,
logging.warning("Skipping message '%s' subject '%s' send to '%s' because it is after %s", uid, subject, message.sent_to[0]['email'],
options.date_before)
return

Expand All @@ -62,20 +64,33 @@ def process_message(filename_template, options, message):

if options.subject_regex_match_anywhere:
if not re.search(options.subject_regex, subject, flags=regex_flags):
logging.warning("Skipping message '%s' subject '%s' because '%s' was not found in the string (case-%sensitive)",
uid, subject, options.subject_regex, "in" if options.subject_regex_ignore_case else "s")
logging.warning("Skipping message '%s' subject '%s' send to '%s' because '%s' was not found in the string (case-%sensitive)",
uid, subject, message.sent_to[0]['email'], options.subject_regex, "in" if options.subject_regex_ignore_case else "s")
return
else:
if not re.match(options.subject_regex, subject, flags=regex_flags):
logging.warning("Skipping message '%s' subject '%s' because it does not start with '%s' (case-%sensitive)",
uid, subject, options.subject_regex, "in" if options.subject_regex_ignore_case else "s")
logging.warning("Skipping message '%s' subject '%s' send to '%s' because it does not start with '%s' (case-%sensitive)",
uid, subject, message.sent_to[0]['email'], options.subject_regex, "in" if options.subject_regex_ignore_case else "s")
return

logging.info("Processing message '%s' subject '%s'", uid, subject)
if options.sent_to_regex:
if not re.search(options.sent_to_regex, message.sent_to[0]['email'], flags=0):
logging.warning("Skipping message '%s' subject '%s' send to '%s' because '%s' was not found in sent_to email",
uid, subject, message.sent_to[0]['email'], options.subject_regex)
return

logging.info("Processing message '%s' subject '%s' send to '%s'", uid, subject, message.sent_to[0]['email'])

for idx, attachment in enumerate(message.attachments):
try:
attachment_filename = QuoPriEncoding.decode(attachment.get('filename'))

if options.filename_regex:
if not re.search(options.filename_regex, attachment_filename, flags=0):
logging.warning("Skipping attachment '%s' because '%s' was not found in filename",
attachment_filename, options.filename_regex)
continue

download_filename = filename_template.render(attachment_name=attachment_filename,
attachment_idx=idx,
subject=subject,
Expand Down Expand Up @@ -124,6 +139,8 @@ if __name__ == '__main__':
parser.add_option("--username", dest="username", help="IMAP Username")
parser.add_option("--password", dest="password", help="IMAP Password")
parser.add_option("--imap-folder", dest="imap_folder", help="IMAP Folder to extract attachments from")
parser.add_option("--filename-regex", dest="filename_regex", help="Regex that the attachment filename must match against")
parser.add_option("--sent-to-regex", dest="sent_to_regex", help="Regex that the sent_to must match against")
parser.add_option("--subject-regex", dest="subject_regex", help="Regex that the subject must match against")
parser.add_option("--subject-regex-ignore-case", dest="subject_regex_ignore_case", action="store_true", default=False, help="Provide this option to ignore regex case in subject.")
parser.add_option("--subject-regex-match-anywhere", dest="subject_regex_match_anywhere", action="store_true", default=False, help="Provide this option to search anywhere in subject")
Expand All @@ -148,6 +165,12 @@ if __name__ == '__main__':

(options, args) = parser.parse_args()

for option,value in options.__dict__.items():
if not value:
value = os.getenv('AD_' + option.upper())
if value:
options.__dict__[option] = value

Logger.setup(options.loglevel)
logging.info(f'Attachment Downloader - Version: {Version.get()} {Version.get_env_info()}')

Expand All @@ -173,42 +196,49 @@ if __name__ == '__main__':

password = options.password if options.password else get_password()

logging.info("Logging in to: '%s' as '%s'", options.host, options.username)
mail = Imbox(options.host,
username=options.username,
password=password,
port=options.port,
ssl=tls,
ssl_context=ssl.create_default_context(),
starttls=starttls)
while True:

logging.info("Logged in to: '%s' as '%s'", options.host, options.username)
logging.info("Logging in to: '%s' as '%s'", options.host, options.username)
mail = Imbox(options.host,
username=options.username,
password=password,
port=options.port,
ssl=tls,
ssl_context=ssl.create_default_context(),
starttls=starttls)

folders = []
logging.info("Logged in to: '%s' as '%s'", options.host, options.username)

if options.imap_folder:
folders = [options.imap_folder]
else:
status, folders = mail.folders()
folders = [folder.decode().split(" \"/\" ")[1] for folder in folders]
folders = [f for f in folders if not f == '"[Gmail]"']
folders = []

if options.imap_folder:
folders = [options.imap_folder]
else:
status, folders = mail.folders()
folders = [folder.decode().split(" \"/\" ")[1] for folder in folders]
folders = [f for f in folders if not f == '"[Gmail]"']

logging.info("Folders: %s", folders)
for folder in folders:
filter_options = build_filter_options()
logging.info("Folders: %s", folders)
for folder in folders:
filter_options = build_filter_options()

try:
messages = mail.messages(**filter_options)
try:
messages = mail.messages(**filter_options)

for (uid, message) in messages:
process_message(filename_template, options, message)
except Exception as e:
logging.error("Failed to process messages for folder '%s'", folder)
logging.exception(e)
for (uid, message) in messages:
process_message(filename_template, options, message)
except Exception as e:
logging.error("Failed to process messages for folder '%s'", folder)
logging.exception(e)

logging.info('Finished processing messages')

logging.info('Finished processing messages')
logging.info('Logging out of: %s', options.host)
mail.logout()

logging.info('Logging out of: %s', options.host)
mail.logout()
if os.getenv("AD_INTERVAL") is None:
break
else:
time.sleep(int(os.getenv("AD_INTERVAL")))

logging.info("Done")

0 comments on commit e27357e

Please sign in to comment.