diff --git a/helpdesk/overrides/email_account.py b/helpdesk/overrides/email_account.py index 6e777f99d8..33b75fe426 100644 --- a/helpdesk/overrides/email_account.py +++ b/helpdesk/overrides/email_account.py @@ -1,5 +1,4 @@ import re -from email import message_from_string import frappe from frappe import _ @@ -58,89 +57,39 @@ def parent_communication(self): class CustomEmailAccount(EmailAccount): def get_inbound_mails(self) -> list[InboundMail]: - """retrive and return inbound mails.""" + """Return the framework's inbound mails, filtered and re-wrapped. + + This used to be a full copy of `EmailAccount.get_inbound_mails`, which meant every + fix the framework made to the fetch loop was silently lost on any site where + helpdesk is installed -- including the per-folder IMAP UID cursor, whose absence + made each poll retrieve only the newest message of every folder. Delegate the + fetching and keep only what is specific to helpdesk: skipping auto-generated + mails, and threading through CustomInboundMail. + """ mails = [] - def process_mail(messages, append_to=None): - for index, message in enumerate(messages.get("latest_messages", [])): - try: - _msg = message_from_string( - message.decode("utf-8", errors="replace") - ) - + for mail in super().get_inbound_mails(): + try: + if mail.mail.get("X-Auto-Generated"): # Important: If the email is auto-generated, we do not create a ticket - if _msg.get("X-Auto-Generated"): - continue - - uid = ( - messages["uid_list"][index] - if messages.get("uid_list") - else None - ) - seen_status = messages.get("seen_status", {}).get(uid) - if self.email_sync_option != "UNSEEN" or seen_status != "SEEN": - _inbound_mail = CustomInboundMail( - message, - self, - frappe.safe_decode(uid), - seen_status, - append_to, - ) - mails.append(_inbound_mail) - except Exception as e: - # Log the error but continue processing other emails - frappe.log_error( - title=_( - "Error processing email at index {0}, message: {1}" - ).format(index, e), - message=frappe.get_traceback(), - ) - self.handle_bad_emails(index, message, frappe.get_traceback()) continue - if not self.enable_incoming: - return [] - - try: - if self.service == "Frappe Mail": - frappe_mail_client = self.get_frappe_mail_client() - messages = frappe_mail_client.pull_raw( - last_received_at=self.last_synced_at - ) - process_mail(messages) - self.db_set( - "last_synced_at", - messages["last_received_at"], - update_modified=False, + mails.append( + CustomInboundMail( + mail.raw_message, + self, + mail.uid, + mail.seen_status, + mail.append_to, + ) ) - else: - email_sync_rule = self.build_email_sync_rule() - email_server = self.get_incoming_server( - in_receive=True, email_sync_rule=email_sync_rule + except Exception as e: + # Log the error but continue processing other emails + frappe.log_error( + title=_("Error processing email {0}, message: {1}").format(mail.uid, e), + message=frappe.get_traceback(), ) - if self.use_imap: - # process all given imap folder - for folder in self.imap_folder: - if email_server.select_imap_folder(folder.folder_name): - email_server.settings["uid_validity"] = folder.uidvalidity - messages = ( - email_server.get_messages( - folder=f'"{folder.folder_name}"' - ) - or {} - ) - process_mail(messages, folder.append_to) - else: - # process the pop3 account - messages = email_server.get_messages() or {} - process_mail(messages) - - # close connection to mailserver - email_server.logout() - except Exception: - self.log_error( - title=_("Error while connecting to email account {0}").format(self.name) - ) - return [] + self.handle_bad_emails(mail.uid, mail.raw_message, frappe.get_traceback()) + continue return mails