diff --git a/README.md b/README.md index f776c89..b864956 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,15 @@ Usage: `kernel-update.py` Alt.: `kernel-update.py ` +## mail-payroll.py +Parse Thunderbird inbox in mailbox format, decrypt and save pdf attachments from selected sender. + +Status: active use + +Dependencies (python): pikepdf +Dependencies (systemd): python3, qpdf + +Usage: Invoke when receiving new mail using systemd path monitoring. ## njalla-tlsa-rotate.py Perform 3 1 1 + 3 1 1 TLSA key rollover for Maddy mailserver with 3h window. Since the script is stateless diff --git a/mail-payroll/mail-payroll.path b/mail-payroll/mail-payroll.path new file mode 100755 index 0000000..a9cb25b --- /dev/null +++ b/mail-payroll/mail-payroll.path @@ -0,0 +1,9 @@ +[Unit] +Description="Run script to save mailed payrolls" + +[Path] +PathChanged=%h/.thunderbird/tjeb38hd.default-release/ImapMail/imap.centrum-2.cz/INBOX-2 +Unit=mail-payroll.service + +[Install] +WantedBy=multi-user.target diff --git a/mail-payroll/mail-payroll.py b/mail-payroll/mail-payroll.py new file mode 100755 index 0000000..b165378 --- /dev/null +++ b/mail-payroll/mail-payroll.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 + +import mailbox +import os +import sys +from email import message, parser, policy +from io import BytesIO +from pathlib import Path + +import pikepdf + +MONITORED_SENDER = 'vyplatnice@disponero.cz' + + +def main(inbox: Path, payroll_save_dir: Path, password: str) -> None: + print('Scanning for new payroll attachments') + attachments = get_payroll_attachments(inbox) + for attachment in attachments: + saved_path = save_pdf(attachment, password, payroll_save_dir) + if saved_path is not None: + print(f'Saved {saved_path}') + print('Done') + + +def get_payroll_attachments(inbox: Path) -> list[message.EmailMessage]: + mbox = mailbox.mbox(inbox, create=False) + mailbox_mails = (msg for msg in mbox.itervalues() if MONITORED_SENDER in msg['From']) + mail_parser = parser.BytesParser(policy=policy.default) + email_mails = (mail_parser.parsebytes(mail.as_bytes()) for mail in mailbox_mails) + attachments = [] + for mail in email_mails: + for attachment in mail.iter_attachments(): + content_type = attachment.get_content_type() + if content_type not in ('application/pdf', 'application/octet-stream'): + continue + attachments.append(attachment) + return attachments + + +def save_pdf(locked_pdf: message.EmailMessage, password: str, dest: Path) -> Path | None: + dest_filename: Path = dest / locked_pdf.get_filename() + if dest_filename.exists(): + return None + pdf_bytes = BytesIO(locked_pdf.get_content()) + with pikepdf.open(pdf_bytes, password=password) as pdf: + pdf.save(dest_filename) + return dest_filename + + +if __name__ == '__main__': + main(Path(sys.argv[1]), Path(sys.argv[2]), os.getenv('PAYROLL_PASSWORD')) diff --git a/mail-payroll/mail-payroll.service b/mail-payroll/mail-payroll.service new file mode 100755 index 0000000..cace772 --- /dev/null +++ b/mail-payroll/mail-payroll.service @@ -0,0 +1,9 @@ +[Unit] +Description=Automatically unlock payroll attachments in mail + +[Service] +EnvironmentFile=%h/.local/share/env/mail-payroll.env +ExecStart=%h/.local/bin/mail-payroll.py %h/.thunderbird/tjeb38hd.default-release/ImapMail/imap.centrum-2.cz/INBOX-2 %h/Nextcloud/Dokumenty/vyplata/disponero + +[Install] +WantedBy=default.target