#!/usr/bin/env python3 from config import config import logging import sendmail import ssl import datetime import email import imaplib import report from bot import Bot logger = logging.getLogger(__name__) class Mailbot(Bot): """ Bot which sends Mails if mentioned via twitter/mastodon, and tells other bots that it received mails. """ def login(self, user): # change to use mailbox of local system mailinglist = user.get_mailinglist() mailbox = imaplib.IMAP4_SSL(mailinglist) context = ssl.create_default_context() try: mailbox.starttls(ssl_context=context) except: logger.error('StartTLS failed', exc_info=True) try: mailbox.login(config["mail"]["user"], config["mail"]["passphrase"]) except imaplib.IMAP4.error: logger.error("Login to mail server failed", exc_info=True) try: mailer = sendmail.Mailer() mailer.send('', config['web']['contact'], 'Ticketfrei Crash Report', attachment=config['logging']['logpath']) except: logger.error('Mail sending failed', exc_info=True) def crawl(self, user): """ crawl for new mails. :return: msgs: (list of report.Report objects) """ mailbox = self.login(user) try: rv, data = mailbox.select("Inbox") except imaplib.IMAP4.abort: logger.error("Crawling Mail failed", exc_info=True) rv = False msgs = [] if rv == 'OK': rv, data = mailbox.search(None, "ALL") if rv != 'OK': return msgs for num in data[0].split(): rv, data = mailbox.fetch(num, '(RFC822)') if rv != 'OK': logger.error("Couldn't fetch mail %s %s" % (rv, str(data))) return msgs msg = email.message_from_bytes(data[0][1]) # check if email was sent by the bot itself. Different solution? if not user.get_mailinglist() in msg['From']: # get a comparable date out of the email date_tuple = email.utils.parsedate_tz(msg['Date']) date_tuple = datetime.datetime.fromtimestamp( email.utils.mktime_tz(date_tuple) ) date = int((date_tuple - datetime.datetime(1970, 1, 1)).total_seconds()) if date > user.get_seen_mail(): msgs.append(self.make_report(msg)) return msgs def post(self, user, report): """ sends reports by other sources to a mailing list. :param report: (report.Report object) """ mailinglist = self.login(user) if report.source is not self: mailer = sendmail.Mailer() mailer.send(report.text, mailinglist, "Warnung: Kontrolleure gesehen") def make_report(self, msg): """ generates a report out of a mail :param msg: email.parser.Message object :return: post: report.Report object """ # get a comparable date out of the email date_tuple = email.utils.parsedate_tz(msg['Date']) date_tuple = datetime.datetime.fromtimestamp( email.utils.mktime_tz(date_tuple) ) date = (date_tuple - datetime.datetime(1970, 1, 1)).total_seconds() author = msg.get("From") # get mail author from email header # :todo take only the part before the @ text = msg.get_payload() post = report.Report(author, "mail", text, None, date) self.last_mail = date return post