1
|
|
|
import base64 |
2
|
|
|
import imaplib |
3
|
|
|
import smtplib |
4
|
|
|
from email.mime.application import MIMEApplication |
5
|
|
|
from email.mime.multipart import MIMEMultipart |
6
|
|
|
from email.mime.text import MIMEText |
7
|
|
|
from os.path import basename |
8
|
|
|
import email |
9
|
|
|
import email.utils |
10
|
|
|
import logging |
11
|
|
|
|
12
|
|
|
logger = logging.getLogger(__name__) |
13
|
|
|
|
14
|
|
|
|
15
|
|
|
class EmailManager: |
16
|
|
|
def __init__(self, stmp_host, stmp_port, imap_host, imap_port, user, password, xoauth2_token=None): |
17
|
|
|
# self.receiver = EmailReceiver( |
18
|
|
|
# host=imap_host, |
19
|
|
|
# port=imap_port, |
20
|
|
|
# user=user, |
21
|
|
|
# password=password, |
22
|
|
|
# xoauth2_token=xoauth2_token |
23
|
|
|
# ) |
24
|
|
|
self.sender = EmailSender( |
25
|
|
|
host=stmp_host, |
26
|
|
|
port=stmp_port, |
27
|
|
|
user=user, |
28
|
|
|
password=password, |
29
|
|
|
xoauth2_token=xoauth2_token |
30
|
|
|
) |
31
|
|
|
|
32
|
|
|
|
33
|
|
|
# class EmailReceiver: |
34
|
|
|
# def __init__(self, host, port, user, password): |
35
|
|
|
# self.host = host |
36
|
|
|
# self.port = port |
37
|
|
|
# self.user = user |
38
|
|
|
# self.password = password |
39
|
|
|
# |
40
|
|
|
# def __enter__(self): |
41
|
|
|
# self.server = imaplib.IMAP4_SSL(self.host, self.port) |
42
|
|
|
# self.server.login(self.user, password=self.password) |
43
|
|
|
# |
44
|
|
|
# return self.server |
45
|
|
|
# |
46
|
|
|
# def __exit__(self, exc_type, exc, exc_tb): |
47
|
|
|
# self.server.close() |
48
|
|
|
# |
49
|
|
|
# def get_mail_attachments(self, mailbox): |
50
|
|
|
# with self as mail: |
51
|
|
|
# mail.select( |
52
|
|
|
# mailbox=mailbox, |
53
|
|
|
# readonly=False |
54
|
|
|
# ) |
55
|
|
|
# |
56
|
|
|
# typ, data = mail.search(None, 'UnSeen') # mail.search(None, 'ALL') |
57
|
|
|
# logger.info("%s %s", typ, data) |
58
|
|
|
# |
59
|
|
|
# for num in data[0].split(): |
60
|
|
|
# typ, data = mail.fetch(num, '(RFC822)') |
61
|
|
|
# raw_email = data[0][1] |
62
|
|
|
# # print('Message %s\n%s\n' % (num, raw_email)) |
63
|
|
|
# |
64
|
|
|
# # converts byte literal to string removing b'' |
65
|
|
|
# raw_email_string = raw_email.decode('utf-8') |
66
|
|
|
# email_message = email.message_from_string(raw_email_string) |
67
|
|
|
# |
68
|
|
|
# xml_data = None |
69
|
|
|
# pdf_data = None |
70
|
|
|
# |
71
|
|
|
# for part in email_message.walk(): |
72
|
|
|
# # this part comes from the snipped I don't understand yet... |
73
|
|
|
# if part.get_content_maintype() == 'multipart': |
74
|
|
|
# continue |
75
|
|
|
# if part.get('Content-Disposition') is None: |
76
|
|
|
# continue |
77
|
|
|
# |
78
|
|
|
# file_name = part.get_filename() |
79
|
|
|
# |
80
|
|
|
# if file_name: |
81
|
|
|
# if file_name.endswith(".xml"): |
82
|
|
|
# if xml_data: |
83
|
|
|
# yield xml_data, pdf_data |
84
|
|
|
# pdf_data = None |
85
|
|
|
# xml_data = part.get_payload(decode=True) |
86
|
|
|
# elif file_name.endswith(".pdf"): |
87
|
|
|
# if pdf_data: |
88
|
|
|
# yield xml_data, pdf_data |
89
|
|
|
# xml_data = None |
90
|
|
|
# pdf_data = part.get_payload(decode=True) |
91
|
|
|
# |
92
|
|
|
# if xml_data or pdf_data: |
93
|
|
|
# yield xml_data, pdf_data |
94
|
|
|
# |
95
|
|
|
# # mail.store( |
96
|
|
|
# # message_set=num, |
97
|
|
|
# # command='+FLAGS', |
98
|
|
|
# # flags='\\Seen' |
99
|
|
|
# # ) |
100
|
|
|
|
101
|
|
|
|
102
|
|
|
def generate_oauth2_string(username, access_token) -> str: |
103
|
|
|
auth_string = 'user=' + username + '\1auth=Bearer ' + access_token + '\1\1' |
104
|
|
|
return base64.b64encode(auth_string.encode()).decode() |
105
|
|
|
|
106
|
|
|
|
107
|
|
|
class EmailSender: |
108
|
|
|
def __init__(self, host, port, user, password, xoauth2_token=None): |
109
|
|
|
self.host = host |
110
|
|
|
self.port = port |
111
|
|
|
self.user = user |
112
|
|
|
self.password = password |
113
|
|
|
self.xoauth2_token = xoauth2_token |
114
|
|
|
|
115
|
|
|
def __enter__(self): |
116
|
|
|
self.server = smtplib.SMTP(host=self.host, port=self.port) |
117
|
|
|
self.server.starttls() # Puts connection to SMTP server in TLS mode |
118
|
|
|
|
119
|
|
|
if self.xoauth2_token: |
120
|
|
|
self.server.ehlo_or_helo_if_needed() |
121
|
|
|
self.server.docmd('AUTH', 'XOAUTH2 ' + generate_oauth2_string(self.user, self.xoauth2_token())) |
122
|
|
|
else: |
123
|
|
|
self.server.login( |
124
|
|
|
user=self.user, |
125
|
|
|
password=self.password |
126
|
|
|
) |
127
|
|
|
return self |
128
|
|
|
|
129
|
|
|
# exc_type, exc, exc_tb |
130
|
|
|
def __exit__(self, exc_type, exc, exc_tb): |
131
|
|
|
self.server.close() |
132
|
|
|
|
133
|
|
|
def send_email(self, subject: str, to_addrs: list, html: str = None, file_attachments=None): |
134
|
|
|
msg = MIMEMultipart() |
135
|
|
|
msg['From'] = self.user |
136
|
|
|
msg['To'] = ", ".join(to_addrs) |
137
|
|
|
msg['Subject'] = subject |
138
|
|
|
if html: |
139
|
|
|
msg.attach(MIMEText(html, _subtype='html')) |
140
|
|
|
|
141
|
|
|
for f in file_attachments or []: |
142
|
|
|
with open(f, "rb") as fil: |
143
|
|
|
part = MIMEApplication( |
144
|
|
|
fil.read(), |
145
|
|
|
Name=basename(f) |
146
|
|
|
) |
147
|
|
|
# After the file is closed |
148
|
|
|
part['Content-Disposition'] = 'attachment; filename="%s"' % basename(f) |
149
|
|
|
msg.attach(part) |
150
|
|
|
|
151
|
|
|
self.server.send_message( |
152
|
|
|
msg=msg |
153
|
|
|
) |
154
|
|
|
|