diff --git a/src/MassEmailSender/MassEmailSender.py b/src/MassEmailSender/MassEmailSender.py index 7fdcfa6..cc46d42 100644 --- a/src/MassEmailSender/MassEmailSender.py +++ b/src/MassEmailSender/MassEmailSender.py @@ -141,13 +141,13 @@ def __init__(self, destination_list: typing.List[jsonParser.target] | None = Non sender_list: typing.List[jsonParser.sender_email_account] | None = None, email_content: EmailMessage | None = None, debug_only=False): + self.num_email_sent = 0 self.destination_list = destination_list if destination_list else [] self.sender_list = sender_list self.email_content = email_content self.debug_only = debug_only self.current_sender = None if sender_list is None else sender_list[0] - self.destination_already_sent_list = [] def export_destination(self, filename): num_destinations = len(self.destination_list) @@ -160,7 +160,7 @@ def export_destination(self, filename): destinations_subset = self.destination_list[start_index:end_index] data = {"email_list": [destination.to_dict() for destination in destinations_subset]} - filename_with_index = f"{filename} - {i+1}_{num_files}.json" + filename_with_index = f"{filename} - {i + 1}_{num_files}.json" with open(filename_with_index, "w") as file: json.dump(data, file, indent=4) @@ -194,33 +194,21 @@ def select_sender(self, index): else: raise Exception(f"Err: currently only {len(self.sender_list)} sender exist, asking for {index}") - def _check_sender_daily_limit(self, callback): - if self.current_sender["daily_send_number"] >= self.current_sender["daily_send_limit"]: - new_sender_index = self.sender_list.sender_list.index(self.current_sender) + 1 - print("Max limit hit, Next select: ", new_sender_index) - - # If reach end of the list, exit - if new_sender_index >= len(self.sender_list): - print("No more available sender, exit") - return True - else: - self.select_sender(new_sender_index) - try: - self.destination_list = self.destination_list[max(self.destination_already_sent_list)+1:] - except: - pass - self.start_sending(callback) - return True - return False - - def _start_sending(self, server, callback): - self.destination_already_sent_list = [] - for index, destination in enumerate(self.destination_list): + def _switch_next_available_sender(self): + new_sender_index = self.sender_list.sender_list.index(self.current_sender) + 1 + if new_sender_index >= len(self.sender_list): + print("No more available sender, exit") + return False + else: + print("Next select: ", new_sender_index) + self.select_sender(new_sender_index) + return True - # Check if sender already sent enough for today - if self._check_sender_daily_limit(callback): - return + def _check_sender_daily_limit(self): + return self.current_sender["daily_send_limit"] - self.current_sender["daily_send_number"] + def _start_sending(self, server, email_list, callback): + for index, destination in enumerate(email_list): if 'From' in self.email_content.keys(): self.email_content.replace_header('From', Header(self.current_sender["username"], 'utf-8')) else: @@ -230,45 +218,49 @@ def _start_sending(self, server, callback): else: self.email_content['To'] = Header(destination.email_address, 'utf-8') - result = True - if not self.debug_only: + if self.debug_only: + print(f"DEBUG_ONLY: Email Sent from {self.current_sender['username']} to {destination['email_address']}") + else: try: server.send_message(self.email_content) + self.current_sender["daily_send_number"] += 1 + print( + f"({index + 1}/{len(self.destination_list):<5})\t{str(self.email_content['From']):<10} -> " + f"{str(self.email_content['To']):<20}") + self.num_email_sent += 1 + callback(self.num_email_sent) except: - result = False - - self.current_sender["daily_send_number"] += 1 - self.destination_already_sent_list.append(index) - if callback: - callback(index, result) - - print( - f"({index + 1}/{len(self.destination_list):<5})\t{str(self.email_content['From']):<10} -> " - f"{str(self.email_content['To']):<20}\t{result}") + break def start_sending(self, callback=None): - if self.debug_only: - print("Fake login successes") - self._start_sending(None, callback) - else: - try: - with SMTP(self.current_sender["host"], self.current_sender["port"], timeout=5) as server: - # server.set_debuglevel(2) - - # Put the SMTP connection in TLS (Transport Layer Security) mode. All SMTP commands that follow will be - # encrypted - server.ehlo() # Identify yourself to an ESMTP server using EHLO - if server.has_extn('STARTTLS'): - print("STARTTLS extension is supported.") - server.starttls() - else: - print("STARTTLS extension is not supported.") - server.ehlo() # re-identify ourselves as an encrypted connection - - login_status = server.login(self.current_sender["username"], self.current_sender["password"]) - # print(f"login_status: {login_status}" ) - self._start_sending(server, callback) - except Exception as e: - print(f"error: {e}") - return False - return True + email_left = self.destination_list[:] + self.num_email_sent = 0 + + while len(email_left) != 0: + num_email_available = self._check_sender_daily_limit() + if num_email_available > 0: + try: + with SMTP(self.current_sender["host"], self.current_sender["port"], timeout=5) as server: + # server.set_debuglevel(2) + # Put the SMTP connection in TLS (Transport Layer Security) mode. + # All SMTP commands that follow will be encrypted + server.ehlo() # Identify yourself to an ESMTP server using EHLO + if server.has_extn('STARTTLS'): + # print("STARTTLS extension is supported.") + server.starttls() + else: + print("STARTTLS extension is not supported.") + server.ehlo() # re-identify ourselves as an encrypted connection + + login_status = server.login(self.current_sender["username"], self.current_sender["password"]) + # print(f"login_status: {login_status}" ) + self._start_sending(server, email_left[:num_email_available], callback) + email_left = email_left[num_email_available:] + except Exception as e: + print(f"error: {e}") + if not self._switch_next_available_sender(): + return + else: + if not self._switch_next_available_sender(): + return False + return True \ No newline at end of file diff --git a/src/gui.pyproject.user b/src/gui.pyproject.user index f665828..3cea737 100644 --- a/src/gui.pyproject.user +++ b/src/gui.pyproject.user @@ -1,10 +1,10 @@ - + EnvironmentId - {118736a9-665e-4b38-866f-3375a1a50e02} + {a00ef515-88c7-4aaa-994f-45d7a056c5c2} ProjectExplorer.Project.ActiveTarget @@ -54,6 +54,7 @@ *.md, *.MD, Makefile false true + true @@ -70,24 +71,56 @@ 0 true - - -fno-delayed-template-parsing - - true - Builtin.BuildSystem + + true + true + Builtin.DefaultTidyAndClazy + 16 + + + + true + ProjectExplorer.Project.Target.0 Desktop - Desktop Qt 6.2.3 MSVC2019 64bit - Desktop Qt 6.2.3 MSVC2019 64bit - qt.qt6.623.win64_msvc2019_64_kit - -1 + Desktop Qt 6.5.0 GCC 64bit + Desktop Qt 6.5.0 GCC 64bit + qt.qt6.650.gcc_64_kit + 0 0 - 5 - 0 + 0 + + /home/shun/private/Project/Email_Collect_May_8_2023/MassEmailSender/src + + + true + Python.PysideBuildStep + /home/shun/.local/bin/pyside6-project + + 1 + Build + Build + ProjectExplorer.BuildSteps.Build + + + 0 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + build + Python.PySideBuildConfiguration + + 1 0 @@ -108,104 +141,17 @@ 2 - G:/Code_and_Shit/MassEmailSender/src/config_json/destination_list.json - PythonEditor.RunConfiguration.G:/Code_and_Shit/MassEmailSender/src/config_json/destination_list.json - G:/Code_and_Shit/MassEmailSender/src/config_json/destination_list.json - {0aaafac5-30dd-4851-903f-4430f134fa93} - G:\Code_and_Shit\MassEmailSender\src\config_json\destination_list.json - false - true - false - true - G:/Code_and_Shit/MassEmailSender/src/config_json - - - true - true - true - - 2 - - G:/Code_and_Shit/MassEmailSender/src/config_json/sender.json - PythonEditor.RunConfiguration.G:/Code_and_Shit/MassEmailSender/src/config_json/sender.json - G:/Code_and_Shit/MassEmailSender/src/config_json/sender.json - G:\Code_and_Shit\MassEmailSender\src\config_json\sender.json - false - true - false - true - G:/Code_and_Shit/MassEmailSender/src/config_json - - - true - true - true - - 2 - - G:/Code_and_Shit/MassEmailSender/src/MassEmailSender/jsonParser.py - PythonEditor.RunConfiguration.G:/Code_and_Shit/MassEmailSender/src/MassEmailSender/jsonParser.py - G:/Code_and_Shit/MassEmailSender/src/MassEmailSender/jsonParser.py - G:\Code_and_Shit\MassEmailSender\src\MassEmailSender\jsonParser.py - false - true - false - true - G:/Code_and_Shit/MassEmailSender/src/MassEmailSender - - - true - true - true - - 2 - - G:/Code_and_Shit/MassEmailSender/src/MassEmailSender/MassEmailSender.py - PythonEditor.RunConfiguration.G:/Code_and_Shit/MassEmailSender/src/MassEmailSender/MassEmailSender.py - G:/Code_and_Shit/MassEmailSender/src/MassEmailSender/MassEmailSender.py - G:\Code_and_Shit\MassEmailSender\src\MassEmailSender\MassEmailSender.py - false - true - false - true - G:/Code_and_Shit/MassEmailSender/src/MassEmailSender - - - true - true - true - - 2 - - G:/Code_and_Shit/MassEmailSender/src/config_json/email_to_send.json - PythonEditor.RunConfiguration.G:/Code_and_Shit/MassEmailSender/src/config_json/email_to_send.json - G:/Code_and_Shit/MassEmailSender/src/config_json/email_to_send.json - G:\Code_and_Shit\MassEmailSender\src\config_json\email_to_send.json - false - true - false - true - G:/Code_and_Shit/MassEmailSender/src/config_json - - - true - true - true - - 2 - - G:/Code_and_Shit/MassEmailSender/src/main.py - PythonEditor.RunConfiguration.G:/Code_and_Shit/MassEmailSender/src/main.py - G:/Code_and_Shit/MassEmailSender/src/main.py - {0aaafac5-30dd-4851-903f-4430f134fa93} - G:\Code_and_Shit\MassEmailSender\src\main.py + main.py + PythonEditor.RunConfiguration./home/shun/private/Project/Email_Collect_May_8_2023/MassEmailSender/src/main.py + /home/shun/private/Project/Email_Collect_May_8_2023/MassEmailSender/src/main.py + /home/shun/private/Project/Email_Collect_May_8_2023/MassEmailSender/src/main.py false true false true - G:/Code_and_Shit/MassEmailSender/src + /home/shun/private/Project/Email_Collect_May_8_2023/MassEmailSender/src - 6 + 1 diff --git a/src/gui/ItemEmailWorker.qml b/src/gui/ItemEmailWorker.qml index de88c04..a631c8f 100644 --- a/src/gui/ItemEmailWorker.qml +++ b/src/gui/ItemEmailWorker.qml @@ -47,7 +47,7 @@ GroupBox { Text { text: "Status: " - width: 200 + width: 50 height: parent.height horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter @@ -57,12 +57,34 @@ GroupBox { Text { id: workerstateText text: backend.emailWorkerStateStr - width: 200 + width: 100 height: parent.height horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: getColor() - font.pointSize: 20 + font.pointSize: 15 + function getColor() { + if (backend.emailWorkerState == 0) { + return "red" + } else if (backend.emailWorkerState == 1 || backend.emailWorkerState == 3 || backend.emailWorkerState == 4) { + return "green" + } else if (backend.emailWorkerState == 2 || backend.emailWorkerState == 5) { + return "white" + } else { + return "white" + } + } + } + + Text { + id: emailNumText + text: "0/0" + width: 100 + height: parent.height + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: getColor() + font.pointSize: 15 function getColor() { if (backend.emailWorkerState == 0) { return "red" @@ -99,8 +121,8 @@ GroupBox { workerstateText.text = backend.emailWorkerStateStr } - function onEmailSendFinished(sent, total) { - workerstateText.text = sent + "/" + total + function onEmailSendUpdate(sent, total) { + emailNumText.text = sent + "/" + total } } } diff --git a/src/gui/WindowsSenderManagement.qml b/src/gui/WindowsSenderManagement.qml index 23dca8c..89c4a3e 100644 --- a/src/gui/WindowsSenderManagement.qml +++ b/src/gui/WindowsSenderManagement.qml @@ -204,7 +204,7 @@ ApplicationWindow { TextField { id: dailyLimitInput width: 200 - text: senderList.get_dict_from_index(comboBox.currentIndex)["daily_send_limit"]? senderList.get_dict_from_index(comboBox.currentIndex)["daily_send_limit"]: "" + text: senderList.get_dict_from_index(comboBox.currentIndex)["daily_send_limit"]? senderList.get_dict_from_index(comboBox.currentIndex)["daily_send_limit"]: 0 } } diff --git a/src/main.py b/src/main.py index d5b5165..7327870 100644 --- a/src/main.py +++ b/src/main.py @@ -172,6 +172,7 @@ def cleanup(self): class Backend(QObject): def __init__(self, engine): super().__init__() + self.email_parser_emailAll = emailall.EmailAll(debug_only=False) self.email_parser_frisbee = Frisbee.Frisbee(log_level=logging.DEBUG, save=False) self.email_parser_pyhunter = PyHunter.PyHunter(pyhunter_API_getter()) @@ -184,7 +185,6 @@ def __init__(self, engine): self.engine.rootContext().setContextProperty("senderList", self.sender_list) # For Sending engine - self.total_sent = 0 self.email_worker = MES.EmailWorker(debug_only=False) self.email_worker.add_sender_list(self.sender_list) self.email_worker.select_sender(0) @@ -213,7 +213,7 @@ def set_system_state(self, new_state: SystemState): destinationEmailListChanged = Signal() emlLoadStateChanged = Signal() emailWorkerStateChanged = Signal() - emailSendFinished = Signal(int, int) + emailSendUpdate = Signal(int, int) # Functions - QML -> Python startSearchingEmail = Signal(str, int) @@ -317,17 +317,19 @@ def removeEmailIndex(self, index): self.email_worker.remove_destination_list(index) self.destinationEmailListChanged.emit() - def email_status_callback(self, destination_index: int, result: bool): - self.total_sent = destination_index + 1 + @Slot(int) + def updateUIOnEmailSent(self, number_sent: int): + self.emailSendUpdate.emit(number_sent, len(self.email_worker.destination_list)) @Slot() def startSending(self): + self.updateUIOnEmailSent(0) self.set_system_state(SystemState.SENDING) - if self.email_worker.start_sending(callback=self.email_status_callback): # (callback=self.email_status_callback): + # TODO: Change email_worker into QThread might be better + if self.email_worker.start_sending(callback=self.updateUIOnEmailSent): self.set_system_state(SystemState.DONE) else: self.set_system_state(SystemState.ERROR) - self.emailSendFinished.emit(self.total_sent, len(self.email_worker.destination_list)) @Slot(int) def handleSelectionChange(self, current_index):