diff options
author | hyfc <[email protected]> | 2018-06-24 14:34:35 +0800 |
---|---|---|
committer | hyfc <[email protected]> | 2020-10-22 11:37:42 +0800 |
commit | 9535e3329a5602979cee23ca4072c199449872b1 (patch) | |
tree | dfcfb032f8ae9dfbcb98a413d5124ca5995fbb21 | |
parent | 49f3ae04c9831aff10a75e2380eab48eac8144b8 (diff) | |
download | telegram-mail-bot-9535e3329a5602979cee23ca4072c199449872b1.tar.gz telegram-mail-bot-9535e3329a5602979cee23ca4072c199449872b1.tar.bz2 telegram-mail-bot-9535e3329a5602979cee23ca4072c199449872b1.zip |
Using pyzmail36 to parse raw mail data
-rw-r--r-- | Pipfile | 2 | ||||
-rw-r--r-- | Pipfile.lock | 97 | ||||
-rw-r--r-- | bot.py | 18 | ||||
-rw-r--r-- | utils/client.py | 63 | ||||
-rw-r--r-- | utils/mail.py | 178 |
5 files changed, 191 insertions, 167 deletions
@@ -6,8 +6,10 @@ name = "pypi" [packages] pytz = "*" python-telegram-bot = "*" +pyzmail36 = "*" [dev-packages] +pylint = "*" [requires] python_version = "3.6" diff --git a/Pipfile.lock b/Pipfile.lock index 49e9354..1862db6 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "f7da4ab6099df3aff82e024a8a850f8e6606a3ee0ecdbbc55e20e22d40864c5e" + "sha256": "65ffd10327170095842dff53978ba96e55245c9e61073a9fca7cc117a9bdf85b" }, "pipfile-spec": 6, "requires": { @@ -44,7 +44,100 @@ ], "index": "pypi", "version": "==2018.4" + }, + "pyzmail36": { + "hashes": [ + "sha256:4ac22b663a2525422b15de7f1ca5e60983e1adb647debd14ae955963d4d6b098" + ], + "index": "pypi", + "version": "==1.0.3" } }, - "develop": {} + "develop": { + "astroid": { + "hashes": [ + "sha256:0ef2bf9f07c3150929b25e8e61b5198c27b0dca195e156f0e4d5bdd89185ca1a", + "sha256:fc9b582dba0366e63540982c3944a9230cbc6f303641c51483fa547dcc22393a" + ], + "version": "==1.6.5" + }, + "colorama": { + "hashes": [ + "sha256:463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda", + "sha256:48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1" + ], + "markers": "sys_platform == 'win32'", + "version": "==0.3.9" + }, + "isort": { + "hashes": [ + "sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af", + "sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", + "sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497" + ], + "version": "==4.3.4" + }, + "lazy-object-proxy": { + "hashes": [ + "sha256:0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33", + "sha256:1b668120716eb7ee21d8a38815e5eb3bb8211117d9a90b0f8e21722c0758cc39", + "sha256:209615b0fe4624d79e50220ce3310ca1a9445fd8e6d3572a896e7f9146bbf019", + "sha256:27bf62cb2b1a2068d443ff7097ee33393f8483b570b475db8ebf7e1cba64f088", + "sha256:27ea6fd1c02dcc78172a82fc37fcc0992a94e4cecf53cb6d73f11749825bd98b", + "sha256:2c1b21b44ac9beb0fc848d3993924147ba45c4ebc24be19825e57aabbe74a99e", + "sha256:2df72ab12046a3496a92476020a1a0abf78b2a7db9ff4dc2036b8dd980203ae6", + "sha256:320ffd3de9699d3892048baee45ebfbbf9388a7d65d832d7e580243ade426d2b", + "sha256:50e3b9a464d5d08cc5227413db0d1c4707b6172e4d4d915c1c70e4de0bbff1f5", + "sha256:5276db7ff62bb7b52f77f1f51ed58850e315154249aceb42e7f4c611f0f847ff", + "sha256:61a6cf00dcb1a7f0c773ed4acc509cb636af2d6337a08f362413c76b2b47a8dd", + "sha256:6ae6c4cb59f199d8827c5a07546b2ab7e85d262acaccaacd49b62f53f7c456f7", + "sha256:7661d401d60d8bf15bb5da39e4dd72f5d764c5aff5a86ef52a042506e3e970ff", + "sha256:7bd527f36a605c914efca5d3d014170b2cb184723e423d26b1fb2fd9108e264d", + "sha256:7cb54db3535c8686ea12e9535eb087d32421184eacc6939ef15ef50f83a5e7e2", + "sha256:7f3a2d740291f7f2c111d86a1c4851b70fb000a6c8883a59660d95ad57b9df35", + "sha256:81304b7d8e9c824d058087dcb89144842c8e0dea6d281c031f59f0acf66963d4", + "sha256:933947e8b4fbe617a51528b09851685138b49d511af0b6c0da2539115d6d4514", + "sha256:94223d7f060301b3a8c09c9b3bc3294b56b2188e7d8179c762a1cda72c979252", + "sha256:ab3ca49afcb47058393b0122428358d2fbe0408cf99f1b58b295cfeb4ed39109", + "sha256:bd6292f565ca46dee4e737ebcc20742e3b5be2b01556dafe169f6c65d088875f", + "sha256:cb924aa3e4a3fb644d0c463cad5bc2572649a6a3f68a7f8e4fbe44aaa6d77e4c", + "sha256:d0fc7a286feac9077ec52a927fc9fe8fe2fabab95426722be4c953c9a8bede92", + "sha256:ddc34786490a6e4ec0a855d401034cbd1242ef186c20d79d2166d6a4bd449577", + "sha256:e34b155e36fa9da7e1b7c738ed7767fc9491a62ec6af70fe9da4a057759edc2d", + "sha256:e5b9e8f6bda48460b7b143c3821b21b452cb3a835e6bbd5dd33aa0c8d3f5137d", + "sha256:e81ebf6c5ee9684be8f2c87563880f93eedd56dd2b6146d8a725b50b7e5adb0f", + "sha256:eb91be369f945f10d3a49f5f9be8b3d0b93a4c2be8f8a5b83b0571b8123e0a7a", + "sha256:f460d1ceb0e4a5dcb2a652db0904224f367c9b3c1470d5a7683c0480e582468b" + ], + "version": "==1.3.1" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "pylint": { + "hashes": [ + "sha256:a48070545c12430cfc4e865bf62f5ad367784765681b3db442d8230f0960aa3c", + "sha256:fff220bcb996b4f7e2b0f6812fd81507b72ca4d8c4d05daf2655c333800cb9b3" + ], + "index": "pypi", + "version": "==1.9.2" + }, + "six": { + "hashes": [ + "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", + "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" + ], + "version": "==1.11.0" + }, + "wrapt": { + "hashes": [ + "sha256:d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6" + ], + "version": "==1.10.11" + } + } } @@ -1,9 +1,8 @@ import logging import os -from utils.mail import EmailClient +from utils.client import EmailClient from telegram import ParseMode -from telegram.constants import MAX_MESSAGE_LENGTH from telegram.ext import (Updater, CommandHandler) @@ -49,22 +48,9 @@ def get_email(bot, update, args): index = args[0] with EmailClient(email_addr, email_passwd) as client: mail = client.get_mail_by_index(index) - subject = "*Subject*: %s\n" % mail.subject - sender = "*From*: %s - %s\n" % (mail.from_nickname, mail.from_account) - date = "*Date*: %s\n" % mail.receivedtime bot.send_message(update.message.chat_id, parse_mode=ParseMode.MARKDOWN, - text=subject+sender+date) - if len(mail.text_content) > MAX_MESSAGE_LENGTH: - text = mail.text_content[0:4096] - bot.send_message(update.message.chat_id, - text=text) - mail.text_content = mail.text_content.lstrip(text) - if mail.text_content: - bot.send_message(update.message.chat_id, - text=mail.text_content) - - + text=mail) def main(): # Create the EventHandler and pass it your bot's token. diff --git a/utils/client.py b/utils/client.py new file mode 100644 index 0000000..07518bb --- /dev/null +++ b/utils/client.py @@ -0,0 +1,63 @@ +import logging +import poplib +from utils.mail import Email + + +logger = logging.getLogger(__name__) + + + +class EmailClient(object): + def __init__(self, email_account, passwd): + self.email_account = email_account + self.password = passwd + self.server = self.connect(self) + + @staticmethod + def connect(self): + # parse the server's hostname from email account + pop3_server = 'pop.'+self.email_account.split('@')[-1] + server = poplib.POP3_SSL(pop3_server) + # display the welcome info received from server, + # indicating the connection is set up properly + logger.info(server.getwelcome().decode('utf8')) + # authenticating + server.user(self.email_account) + server.pass_(self.password) + return server + + def get_mails_list(self): + _, mails, _ = self.server.list() + return mails + + def get_mails_count(self): + mails = self.get_mails_list() + return len(mails) + + def get_mail_by_index(self, index): + resp_status, mail_lines, mail_octets = self.server.retr(index) + return Email(mail_lines) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + if exc_type is None: + print('exited normally\n') + self.server.quit() + else: + print('raise an exception! ' + str(exc_type)) + self.server.close() + return False # Propagate + + + +if __name__ == '__main__': + useraccount = "XXXXX" + password = "XXXXXX" + + client = EmailClient(useraccount, password) + num = client.get_mails_count() + print(num) + for i in range(1, num): + print(client.get_mail_by_index(i))
\ No newline at end of file diff --git a/utils/mail.py b/utils/mail.py index 2ead9ae..491faa8 100644 --- a/utils/mail.py +++ b/utils/mail.py @@ -1,149 +1,29 @@ -import base64 -from datetime import datetime -from email.parser import Parser -import logging -import poplib -import pytz -import re - - -logger = logging.getLogger(__name__) - -class MailDetails(object): - def __init__(self): - self.from_nickname = "" - self.from_account = "" - self.to_nickname = "" - self.to_account = "" - self.subject = "" - self.receivedtime = "" - self.text_content = "" - self.html_content = "" - - -def decode_byte(bstr, charset='utf8'): - return bstr.decode(charset) - -def get_rawcontent_charset(rawcontent): - for item in rawcontent: - if decode_byte(item).find('charset='): - charset = re.findall(re.compile('charset="(.*)"'), decode_byte(item)) - for member in charset: - if member is not None: - return member - - -def parse_raw_mail_data(raw_lines, charset='utf8'): - msg_content = b'\r\n'.join(raw_lines).decode(encoding=charset) - return Parser().parsestr(text=msg_content) - -def decode_base64(s, charset='utf8'): - return str(base64.decodebytes(s.encode(encoding=charset)), encoding=charset) - - -def get_mail_info(s): - try: - nickname, account = s.split(" ") - except ValueError: - nickname = '' - account = s - - account = account.lstrip('<') - account = account.rstrip('>') - return nickname, account - -def get_mail_details(msg): - maildetails = MailDetails() - - fromstr = msg.get('From') - from_nickname, from_account = get_mail_info(fromstr) - maildetails.from_nickname = from_nickname - maildetails.from_account = from_account - tostr = msg.get('To') - to_nickname, to_account = get_mail_info(tostr) - maildetails.to_nickname = to_nickname - maildetails.to_account = to_account - - subject = msg.get('Subject') - try: - maildetails.subject = decode_base64(subject.split("?")[3], charset=subject.split("?")[1]) - except IndexError: - maildetails.subject = subject - received_time = msg.get("Date") - maildetails.receivedtime = received_time - - parts = msg.get_payload() - content_charset = parts[0].get_content_charset() - content = parts[0].as_string().split('base64')[-1] - try: - maildetails.text_content = decode_base64(content, content_charset) - except Exception as e: - logger.error('Exception caught: "%s"', e) - maildetails.text_content = content - content = parts[1].as_string().split('base64')[-1] - maildetails.html_content = content - - return maildetails - -class EmailClient(object): - def __init__(self, email_account, passwd): - self.email_account = email_account - self.password = passwd - self.server = self.connect(self) - - @staticmethod - def connect(self): - # parse the server's hostname from email account - pop3_server = 'pop.'+self.email_account.split('@')[-1] - - server = poplib.POP3_SSL(pop3_server) - - # display the welcome info received from server, - # indicating the connection is set up properly - print(server.getwelcome().decode('utf8')) - - # authenticating - server.user(self.email_account) - server.pass_(self.password) - - return server - - def get_mails_list(self): - _, mails, _ = self.server.list() - return mails - - def get_mails_count(self): - mails = self.get_mails_list() - return len(mails) - - - - def get_mail_by_index(self, index): - resp_status, mail_lines, mail_octets = self.server.retr(index) - content_charset = get_rawcontent_charset(mail_lines) - data = parse_raw_mail_data(mail_lines, charset=content_charset or 'utf-8') - maildetails = get_mail_details(data) - return maildetails - - - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - if exc_type is None: - print('exited normally\n') - self.server.quit() - else: - print('raise an exception! ' + str(exc_type)) - self.server.close() - return False # Propagate - - - -if __name__ == '__main__': - useraccount = "XXXXX" - password = "XXXXXX" - - client = EmailClient(useraccount, password) - client.get_mails_count()
\ No newline at end of file +from pyzmail import PyzMessage, decode_text + +class Email(object): + def __init__(self, raw_mail_lines): + msg_content = b'\r\n'.join(raw_mail_lines) + msg = PyzMessage.factory(msg_content) + + self.subject = msg.get_subject() + self.sender = msg.get_address('from') + self.date = msg.get_decoded_header('date', '') + self.id = msg.get_decoded_header('message-id', '') + + for mailpart in msg.mailparts: + if mailpart.is_body=='text/plain': + payload, used_charset=decode_text(mailpart.get_payload(), mailpart.charset, None) + self.charset = used_charset + self.text = payload + return + else: + self.text = None + + def __repr__(self): + mail_str = "Subject: %s\n" % self.subject + mail_str += "From: %s %s\n" % self.sender + mail_str += "Date: %s\n" % self.date + mail_str += "ID: %s\n" % self.id + if self.text: + mail_str += "Text: %s\n" % self.text + return mail_str |