diff --git a/pymailer.py b/pymailer.py new file mode 100644 index 0000000..34ef704 --- /dev/null +++ b/pymailer.py @@ -0,0 +1,110 @@ +import argparse +import smtplib +from imapclient import IMAPClient +from email.message import EmailMessage +from email import message_from_bytes +from email.utils import localtime + +def send_mail(args): + + msg = EmailMessage() + + # Create email body + msg.set_content(args.body) + + # Set email headers + msg['Subject'] = args.subject + msg['From'] = args.from_addr + msg['To'] = args.to_addr + msg['Date'] = localtime() + + smtpObj = smtplib.SMTP_SSL(host=args.smtp_host) + smtpObj.set_debuglevel(args.debug_level) + smtpObj.login(args.smtp_user, args.smtp_password) + smtpObj.send_message(msg) + +def message_list(args): + + imap = IMAPClient(args.imap_host) + imap.login(args.imap_user, args.imap_password) + imap.select_folder(args.folder, readonly=True) + messages = imap.search(['FROM', '']) + for uid, message_data in imap.fetch(messages, "RFC822").items(): + email_message = message_from_bytes(message_data[b"RFC822"]) + print(uid, email_message) + imap.logout() + +def message_search(args): + + imap = IMAPClient(args.imap_host) + imap.login(args.imap_user, args.imap_password) + imap.select_folder(args.folder, readonly=True) + messages = imap.search(args.search_string) + for uid, message_data in imap.fetch(messages, "RFC822").items(): + email_message = message_from_bytes(message_data[b"RFC822"]) + print(uid, email_message) + imap.logout() + +def message_delete(args): + + imap = IMAPClient(args.imap_host) + imap.login(args.imap_user, args.imap_password) + + if args.dry_run == 'true': + print('--dry_run is true, opening IMAP folder as readonly. No actions will be persistent') + imap.select_folder(args.folder, readonly=True) + else: + imap.select_folder(args.folder) + messages = imap.search(args.search_string) + for uid, message_data in imap.fetch(messages, "RFC822").items(): + email_message = message_from_bytes(message_data[b"RFC822"]) + date = email_message.get("Date") + from_addr = email_message.get("From") + to_addr = email_message.get("To") + subject = email_message.get("Subject") + imap.delete_messages(uid) + imap.expunge(uid) + print('\nMessage with uid %s deleted:\n%s\nFrom: %s\nTo: %s\nSubject: %s' % (uid, date, from_addr, to_addr, subject)) + imap.logout() + +# Setup CLI options and help menu +global_parser = argparse.ArgumentParser(prog="pymailer", description="Simple mail client for sending emails, and checking and manipulating an inbox") +subparsers = global_parser.add_subparsers(title="subcommands", help="available subcommands", dest="subcommand", required=True) + +send_mail_parser = subparsers.add_parser("send", help="send an email") +send_mail_parser.add_argument('--smtp_host', help="SMTP server hostname", required=True) +send_mail_parser.add_argument('--smtp_user', help="SMTP server logon username", required=True) +send_mail_parser.add_argument('--smtp_password', help="SMTP server logon password", required=True) +send_mail_parser.add_argument('--from_addr', help="Address to send email from", required=True) +send_mail_parser.add_argument('--to_addr', help="Address to send email to", required=True) +send_mail_parser.add_argument('--subject', help="Email subject", required=True) +send_mail_parser.add_argument('--body', help="Email body", required=True) +send_mail_parser.add_argument('--debug_level', help="Debug level, higher number is more verbose", type=int, choices=range(0, 3), default=0) +send_mail_parser.set_defaults(func=send_mail) + +message_list_parser = subparsers.add_parser("message_list", help="lists all messages in an inbox via IMAP") +message_list_parser.add_argument('--imap_host', help="IMAP server hostname", required=True) +message_list_parser.add_argument('--imap_user', help="IMAP server logon username", required=True) +message_list_parser.add_argument('--imap_password', help="IMAP server logon password", required=True) +message_list_parser.add_argument('--folder', help="Inbox folder", default='INBOX') +message_list_parser.set_defaults(func=message_list) + +message_search_parser = subparsers.add_parser("message_search", help="search an inbox for messages via IMAP") +message_search_parser.add_argument('--imap_host', help="IMAP server hostname", required=True) +message_search_parser.add_argument('--imap_user', help="IMAP server logon username", required=True) +message_search_parser.add_argument('--imap_password', help="IMAP server logon password", required=True) +message_search_parser.add_argument('--folder', help="Inbox folder", default='INBOX') +message_search_parser.add_argument('--search_string', help="Search string e.g 'FROM' 'user@example.com'. Space separated", nargs='*', required=True) +message_search_parser.set_defaults(func=message_search) + +message_delete_parser = subparsers.add_parser("message_delete", help="deletes messages in an inbox via IMAP") +message_delete_parser.add_argument('--imap_host', help="IMAP server hostname", required=True) +message_delete_parser.add_argument('--imap_user', help="IMAP server logon username", required=True) +message_delete_parser.add_argument('--imap_password', help="IMAP server logon password", required=True) +message_delete_parser.add_argument('--folder', help="Inbox folder", default='INBOX') +message_delete_parser.add_argument('--search_string', help="Search string for emails that will be deleted e.g 'FROM' 'user@example.com'. Space separated", nargs='*', required=True) +message_delete_parser.add_argument('--dry_run', help="List emails that will be deleted, but don't delete them", choices=('true', 'false'), default='false') +message_delete_parser.set_defaults(func=message_delete) + +args = global_parser.parse_args() +args.func(args) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..4de4db6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +imapclient