aboutsummaryrefslogtreecommitdiff
path: root/utils/mail.py
blob: f26e7b814ea7fb201910194dc8aaa9ce26cd4a6a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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")
    time_str_fmt = "%a, %d %b %Y %H:%M:%S %z"
    time_obj = datetime.strptime(received_time, time_str_fmt)
    time_obj = time_obj.astimezone(pytz.timezone('Asia/Hong_Kong'))
    maildetails.receivedtime = time_obj.strftime(time_str_fmt)

    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()