-
Notifications
You must be signed in to change notification settings - Fork 0
/
mailclient.py
162 lines (116 loc) · 3.56 KB
/
mailclient.py
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
153
154
155
156
157
158
159
160
161
162
"""
Simple mail client based on SMTPlib and IMAPlib
SSL supported
Client is thread
Tested on greenmail/stanalone
"""
import time
import email
import queue
import smtplib
import imaplib
import threading
from config import SERVER_DOMAIN, SMTP_PORT, IMAP_PORT, MESSAGE_CHECK_COOLDOWN, \
USE_SSL, LOGIN, PASSWORD, INBOX_FOLDER, INGNORE_ALREADY_RECIEVED_MESSAGES
__author__ = 'Yegor Yershov'
class MailClient(threading.Thread):
def __init__(self, logging=False):
"""
Initting super, settings setting
"""
super().__init__(daemon=True)
self.logging = logging
self.new_emails_queue = queue.Queue()
self.login = LOGIN
self.password = PASSWORD
self.use_ssl = USE_SSL
self.inbox = [[], self.load_inbox()][INGNORE_ALREADY_RECIEVED_MESSAGES]
self.catch = True
def smtp_authorize(self):
"""
SMTP authorization to server
"""
if self.use_ssl:
smtp = smtplib.SMTP_SSL(SERVER_DOMAIN, SMTP_PORT)
else:
smtp = smtplib.SMTP(SERVER_DOMAIN, SMTP_PORT)
status = smtp.ehlo() # using ESMTP
if status[0] != 250: # 250 means "everything is fine"
raise RuntimeError(f'Server hello responce is {status[0]}: """{status[1].decode()}"""')
#self.log(f'status: {status}')
status = smtp.login(self.login, self.password)
if status[0] != 235: # 235 means login is successfull
raise RuntimeError(f'Server login failed: {status[1]}')
#self.log('login is successful')
return smtp
def imap_authorize(self):
"""
IMAP authorization to server
"""
if self.use_ssl:
imap = imaplib.IMAP4_SSL(host=SERVER_DOMAIN, port=IMAP_PORT)
else:
imap = imaplib.IMAP4(host=SERVER_DOMAIN, port=IMAP_PORT)
status = imap.login(self.login, self.password)
if status[0] != 'OK':
raise RuntimeError(f'Server login failed: {status[1]}')
return imap
def log(self, message:str, priority:bool=False):
"""
Writes logs if they are turned on
"""
if self.logging or priority:
print(f'[INFO] {message}')
def send_message(self, reciever:str, message:str):
"""
Send direct message
"""
smtp = self.smtp_authorize()
responce = smtp.sendmail(LOGIN, reciever, message)
self.log(f'Message has been sent to {reciever} {responce}')
def load_inbox(self):
"""
Returns list, containing "email.message.Message" structures fromed of messages from INBOX
email.message.Message.items() - return all message add. info (subject, date)
(use get_payload() to get payload)
"""
imap = self.imap_authorize()
status, messages_indexes = imap.select(INBOX_FOLDER)
messages_amount = int(messages_indexes[0])
messages = []
for i in range(messages_amount, 0, -1):
message = imap.fetch(str(i), "(RFC822)")[1]
for responce in message:
if isinstance(responce, tuple):
messages.append(email.message_from_bytes(responce[1]))
return messages
def find_new_messages(self, first:list, second:list):
"""
Iterates by lists of emails, comparing payloads and items
"""
new = []
for mail in first:
flag = True
for mail2 in second:
if mail.get_payload() == mail2.get_payload() and mail.items() == mail2.items():
flag = False
break
if flag:
new.append(mail)
return new
def run(self):
"""
Main thread function, updating inbox
"""
self.smtp_authorize()
while self.catch:
inbox = self.load_inbox()
for mail in self.find_new_messages(inbox, self.inbox):
self.new_emails_queue.put(mail)
self.log('New message!')
self.inbox = inbox
time.sleep(MESSAGE_CHECK_COOLDOWN)
if __name__ == '__main__':
main_thread = MailClient(logging=True) # console logging on
main_thread.start()
main_thread.join()