22
22
from email_content import html_content
23
23
from utils import read_email_list
24
24
from email_extractor import extracted_emails
25
- from PyQt6 .QtCore import QThread
25
+ from PyQt6 .QtCore import QThread , pyqtSignal , QObject
26
+
26
27
27
28
28
29
29
30
30
31
class EmailAutomationApp (QMainWindow ):
32
+ log_signal = pyqtSignal (str )
31
33
def __init__ (self ):
32
34
super ().__init__ ()
33
-
35
+ self . log_signal . connect ( self . update_log_output ) # اتصال سیگنال به متد
34
36
self .setWindowTitle ("Email Automation Tool" )
35
37
self .setGeometry (100 , 100 , 800 , 600 )
36
38
@@ -42,7 +44,11 @@ def __init__(self):
42
44
self .create_link_extractor_tab ()
43
45
self .create_email_extractor_tab () # New tab for extracting emails from URLs
44
46
self .create_email_sender_tab ()
45
- # =======================end tab===============================
47
+ #============================signals=======================
48
+ def update_log_output (self , message ):
49
+ self .log_output .append (message ) # به روز رسانی لاگ در ترد اصلی
50
+ # ==========================================================
51
+ # =======================end tab===============================
46
52
# ================== start tab ==================
47
53
def create_link_extractor_tab (self ):
48
54
"""Tab for extracting links from search results"""
@@ -335,6 +341,7 @@ def save_email_to_file(self):
335
341
QMessageBox .critical (self , "Error" , f"An error occurred while saving the file: { e } " )
336
342
# ===========================end extract email ==================
337
343
# ======================== start email sending======================
344
+
338
345
def browse_file (self ):
339
346
"""Open a file dialog to select a file."""
340
347
file_name , _ = QFileDialog .getOpenFileName (self , "Select File" , "" , "All Files (*)" )
@@ -346,10 +353,12 @@ def start_email_sending(self):
346
353
sender_email = self .sender_email_input .text ()
347
354
password = self .password_input .text ()
348
355
email_file = self .email_file_input .text ()
349
- attachment_path = self .attachment_input .text () # گرفتن مسیر فایل از QLineEdit
350
-
351
- if sender_email and password and email_file and attachment_path :
352
- threading .Thread (target = self .send_emails , args = (sender_email , password , email_file , attachment_path ), daemon = True ).start ()
356
+ attachment_path = self .attachment_input .text () # Get the file path from QLineEdit
357
+ attachment_path if attachment_path else None
358
+ if sender_email and password and email_file :
359
+
360
+ attachment_path = attachment_path if attachment_path else None
361
+ threading .Thread (target = self .send_emails , args = (sender_email , password , email_file , attachment_path ), daemon = False ).start ()
353
362
else :
354
363
QMessageBox .warning (self , "Input Error" , "Please fill in all fields." )
355
364
@@ -358,27 +367,38 @@ def send_emails(self, sender_email, password, email_file, attachment_path):
358
367
"""Function to send emails to extracted email addresses with attachment"""
359
368
asyncio .run (self .send_emails_async (sender_email , password , email_file , attachment_path ))
360
369
361
-
362
370
async def send_emails_async (self , sender_email , password , email_file , attachment_path ):
363
371
"""Asynchronous email sending with attachment"""
364
372
try :
365
373
email_list = await read_email_list (email_file )
366
-
367
- tasks = []
368
374
for receiver_email in email_list :
369
- tasks .append (send_email (
370
- receiver_email = receiver_email ,
371
- html_content = html_content ,
372
- sender_email = sender_email ,
373
- password = password ,
374
- attachment_path = attachment_path # استفاده از مسیر جدید
375
- ))
376
- await asyncio .gather (* tasks ) # Send emails concurrently
375
+ await self .send_email_with_retry (receiver_email , sender_email , password , attachment_path )
376
+ await asyncio .sleep (10 ) # Delay of 10 seconds between each email to avoid rate limits
377
+
377
378
self .log_output .append ("Emails sent successfully!" )
378
379
QMessageBox .information (self , "Success" , "Emails sent successfully!" )
379
380
except Exception as e :
380
381
QMessageBox .critical (self , "Error" , f"An error occurred while sending emails: { e } " )
381
382
383
+ async def send_email_with_retry (self , receiver_email , sender_email , password , attachment_path = None , retries = 3 , delay = 5 ):
384
+ """Send email with retry mechanism"""
385
+ for attempt in range (retries ):
386
+ try :
387
+ await send_email (
388
+ receiver_email = receiver_email ,
389
+ html_content = html_content ,
390
+ sender_email = sender_email ,
391
+ password = password ,
392
+ attachment_path = attachment_path
393
+ )
394
+ self .log_signal .emit (f"Email sent successfully to { receiver_email } !" )
395
+ break # If successful, exit the retry loop
396
+ except Exception as e :
397
+ self .log_signal .emit (f"Failed to send email to { receiver_email } : { e } " )
398
+ if attempt < retries - 1 :
399
+ await asyncio .sleep (delay ) # Wait before retrying
400
+ else :
401
+ self .log_signal .emit (f"Giving up on sending email to { receiver_email } after { retries } attempts." ) # استفاده از سیگنال
382
402
# ======================== end email sending =====================
383
403
384
404
0 commit comments