-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
296 lines (241 loc) · 11.3 KB
/
main.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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import streamlit as st
import pandas as pd
from typing import List, Optional
from dataclasses import dataclass
import logging
from pathlib import Path
import sys
from streamlit_quill import st_quill
from PIL import Image
def update_access_counter():
try:
with open('access_counter.txt', 'r') as f:
count = int(f.read())
except FileNotFoundError:
count = 0
count += 1
with open('access_counter.txt', 'w') as f:
f.write(str(count))
return count
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('email_sender.log'),
logging.StreamHandler(sys.stdout)
]
)
@dataclass
class EmailConfig:
"""Classe para armazenar configurações de email"""
smtp_user: str
smtp_password: str
smtp_server: str = "smtp.gmail.com"
smtp_port: int = 587
class EmailSender:
"""Classe responsável pelo envio de emails"""
def __init__(self, config: EmailConfig):
self.config = config
def send_email(self, to_email: str, subject: str, body: str) -> bool:
"""
Envia um email individual
Retorna True se o envio for bem sucedido, False caso contrário
"""
try:
msg = MIMEMultipart()
msg['Subject'] = subject
msg['From'] = self.config.smtp_user
msg['To'] = to_email
msg['Reply-To'] = '[email protected]'
msg.attach(MIMEText(body, 'html'))
with smtplib.SMTP(self.config.smtp_server, self.config.smtp_port) as server:
server.starttls()
server.login(self.config.smtp_user, self.config.smtp_password)
server.sendmail(msg['From'], [msg['To']], msg.as_string())
logging.info(f"Email enviado com sucesso para: {to_email}")
return True
except Exception as e:
logging.error(f"Erro ao enviar email para {to_email}: {str(e)}")
return False
class EmailProcessor:
"""Classe para processar lista de emails"""
@staticmethod
def validate_email(email: str) -> bool:
"""Validação básica de email"""
return isinstance(email, str) and '@' in email and '.' in email
@staticmethod
def process_excel(file, email_column: str) -> List[str]:
"""Processa arquivo Excel e retorna lista de emails válidos"""
try:
df = pd.read_excel(file)
emails = df[email_column].dropna().tolist()
return [email for email in emails if EmailProcessor.validate_email(email)]
except Exception as e:
logging.error(f"Erro ao processar arquivo Excel: {str(e)}")
raise
class StreamlitUI:
"""Interface do usuário Streamlit"""
def __init__(self):
self.config = None
self.set_page_config()
def set_page_config(self):
"""Configuracao da página"""
st.set_page_config(
page_title="Envio de Emails",
page_icon='📧',
layout="wide",
initial_sidebar_state="expanded"
)
def sidebar(self):
"""Configura a barra lateral"""
st.sidebar.header("Configurações", divider=True)
st.sidebar.info("Digite suas informações de email e senha do google apps.")
smtp_user = st.sidebar.text_input("Digite seu e-mail")
smtp_password = st.sidebar.text_input(
"Digite sua senha",
placeholder="Senha apps google",
type="password"
)
if smtp_user and smtp_password:
self.config = EmailConfig(smtp_user=smtp_user, smtp_password=smtp_password)
self.show_help_section()
def show_help_section(self):
"""Exibe seção de ajuda"""
st.sidebar.header("Ajuda", divider=True)
st.sidebar.info("Clique em Download para baixar o tutorial de como criar a senha no google apps.")
self.download_tutorial()
st.sidebar.markdown("""
💜 Gostou do projeto? Me pague um café!
**PIX:** [email protected]""")
def download_tutorial(self):
"""Gerencia download do tutorial"""
tutorial_path = Path("Como configurar uma senha.pdf")
if tutorial_path.exists():
with open(tutorial_path, "rb") as f:
st.sidebar.download_button(
"⬇️ Download",
f,
file_name=tutorial_path.name
)
def main_page(self):
"""Página principal"""
st.header("SISTEMA DE ENVIO DE E-MAILS EM MASSA", divider=True)
subject = st.text_input("Digite o assunto do e-mail", placeholder="Assunto do e-mail")
# Editor rico para o corpo do email
st.subheader("Corpo do E-mail")
st.info("Use o editor abaixo para formatar seu email. Você pode adicionar formatação, links e imagens.")
# Configuração do editor Quill
email_body = st_quill(
placeholder="Digite o conteúdo do seu email aqui...",
html=True,
key="quill",
toolbar=[
['bold', 'italic', 'underline', 'strike'],
['blockquote', 'code-block'],
[{'header': 1}, {'header': 2}],
[{'list': 'ordered'}, {'list': 'bullet'}],
[{'script': 'sub'}, {'script': 'super'}],
[{'indent': '-1'}, {'indent': '+1'}],
['link', 'image'],
[{'size': ['small', False, 'large', 'huge']}],
[{'color': []}, {'background': []}],
['clean']
]
)
single_recipient = st.text_input(
"Digite o e-mail do destinatário único (opcional)",
placeholder="[email protected]"
)
file = st.file_uploader("Ou carregue uma lista de e-mails (.xlsx)", type="xlsx")
email_column = None
if file:
try:
df = pd.read_excel(file)
st.write("Colunas encontradas no arquivo:", list(df.columns))
email_column = st.selectbox(
"Selecione a coluna que contém os emails:",
options=list(df.columns)
)
except Exception as e:
st.error(f"Erro ao ler arquivo: {str(e)}")
return
if st.button("Enviar e-mail"):
self.handle_send_button(single_recipient, file, email_column, subject, email_body)
def handle_send_button(self, single_recipient, file, email_column, subject, body):
"""Processa o envio de emails"""
if not self.config:
st.error("Configure seu email e senha nas configurações!")
return
try:
emails = self.get_email_list(single_recipient, file, email_column)
if not emails:
st.warning("Nenhum email válido encontrado para envio.")
return
self.send_bulk_emails(emails, subject, body)
except Exception as e:
st.error(f"Erro no processamento: {str(e)}")
logging.error(f"Erro no processamento: {str(e)}")
def get_email_list(self, single_recipient, file, email_column) -> List[str]:
"""Obtém lista de emails para envio"""
if single_recipient and EmailProcessor.validate_email(single_recipient):
return [single_recipient]
elif file and email_column:
return EmailProcessor.process_excel(file, email_column)
return []
def send_bulk_emails(self, emails: List[str], subject: str, body: str):
"""Envia emails em massa com barra de progresso"""
total = len(emails)
progress_bar = st.progress(0)
status_text = st.empty()
sender = EmailSender(self.config)
successes = 0
for idx, email in enumerate(emails):
if sender.send_email(email, subject, body):
successes += 1
progress = (idx + 1) / total
progress_bar.progress(progress)
status_text.text(f"Processando: {idx + 1} de {total} emails")
self.show_completion_message(successes, total)
def show_completion_message(self, successes: int, total: int):
"""Exibe mensagem de conclusão"""
if successes == total:
st.success(f"Todos os {total} emails foram enviados com sucesso!")
else:
st.warning(f"Enviados {successes} de {total} emails. Alguns envios falharam.")
def show_terms_and_conditions():
st.title("Termo de Uso e Política de Privacidade")
st.markdown("""
## Termo de Uso
A utilização deste sistema de envio de emails em massa está sujeita aos seguintes termos:
1. **Uso Autorizado**: O sistema é fornecido para uso pessoal ou empresarial legítimo. Você concorda em não utilizá-lo para fins ilegais, spam ou atividades prejudiciais.
2. **Propriedade Intelectual**: Todo o conteúdo, design e funcionalidades do sistema são de propriedade da Envio de emails e estão protegidos por leis de propriedade intelectual. Você não possui direitos de propriedade sobre esses elementos.
3. **Limitação de Responsabilidade**: A Envio de emails não se responsabiliza por quaisquer danos decorrentes do uso deste sistema. Você é o único responsável por garantir que seus envios estejam de acordo com as leis aplicáveis.
4. **Modificações**: Estes Termos de Uso podem ser atualizados periodicamente. É sua responsabilidade verificar por possíveis atualizações.
## Política de Privacidade
A Envio de emails valoriza sua privacidade. Ao utilizar este sistema, você concorda com as seguintes práticas:
1. **Coleta de Dados**: Coletamos endereços de email fornecidos por você ou obtidos de listas aprovadas. Esses dados serão utilizados apenas para o envio de emails.
2. **Uso de Dados**: Usaremos seus dados de email apenas para o envio de campanhas. Não compartilharemos seus dados com terceiros, exceto se necessário para a prestação deste serviço.
3. **Armazenamento de Dados**: Seus dados de email serão armazenados de forma segura e seram excluídos após a atualização da pagina.
## Consentimento
Ao utilizar este sistema de envio de emails, você declara ter lido e concordado com os Termos de Uso e a Política de Privacidade acima.
""")
agree = st.checkbox("Eu li e aceito os Termos de Uso e Política de Privacidade")
if agree:
st.session_state['accepted_terms'] = True
st.rerun()
def main():
if 'accepted_terms' not in st.session_state:
st.session_state['accepted_terms'] = False
if not st.session_state['accepted_terms']:
show_terms_and_conditions()
else:
ui = StreamlitUI()
ui.sidebar()
ui.main_page()
access_count = update_access_counter()
st.sidebar.markdown(f"👥 Número de acessos: {access_count}")
if __name__ == "__main__":
main()