44import email as email_existing
55import email .mime .text
66import email .policy
7- from datetime import datetime
87from email .header import decode_header , make_header
98from email .message import EmailMessage
109from email .message import Message
2322from app .utils .maths .crypto_utils import decrypt_password
2423from app .utils .module .importManager import import_and_instantiate_manager
2524from app .utils .logger .logger import logger_mail_server
26- from app .utils .strings import get_imap_config_from_url , get_domain_from_mail , get_domain_from_contact , escape_imap_string
25+ from app .utils .strings import get_imap_config_from_url , get_domain_from_mail , get_domain_from_contact
2726from app .utils .constants import DELETE_MAIL_BEHAVIOR_MAP
2827
2928if TYPE_CHECKING :
@@ -717,9 +716,9 @@ def get_folder_mails(self, account_id: str, folder_name: str, collection_param:
717716 def search_mails (self , account_id : str , search_params : dict , collection_param : CollectionPaginateArgs ) -> tuple [list [dict [str , Any ]], int ]:
718717 """Execute an advanced search across one or multiple folders.
719718
720- Builds an IMAP SEARCH criteria string from ``search_params``, queries
721- each requested folder and returns a paginated list of matching mails together
722- with the total count.
719+ Delegates the building of the protocol-specific search criteria (IMAP SEARCH
720+ syntax, JMAP filter, ...) to the mail client, queries each requested folder
721+ and returns a paginated list of matching mails together with the total count.
723722
724723 :param account_id: The account identifier.
725724 :type account_id: str
@@ -729,7 +728,7 @@ def search_mails(self, account_id: str, search_params: dict, collection_param: C
729728 :type collection_param: CollectionPaginateArgs
730729 :return: A tuple of (list of mail dicts, total count).
731730 :rtype: tuple[list[dict[str, Any]], int]
732- :raises RequestException: If IMAP operations fail or dates are invalid.
731+ :raises RequestException: If mail server operations fail or search_params are invalid.
733732 """
734733 client = self ._open_client_for (account_id )
735734
@@ -738,64 +737,8 @@ def search_mails(self, account_id: str, search_params: dict, collection_param: C
738737 without_content = not fields_params ["with_content" ]
739738 include_deleted = fields_params ["include_deleted" ]
740739
741- # --- Build IMAP SEARCH criteria ---
742- criteria_parts : list [str ] = []
743- if not include_deleted :
744- criteria_parts .append ("NOT DELETED" )
745-
746- if search_params .get ("text" ):
747- criteria_parts .append (f'TEXT "{ search_params ["text" ]} "' )
748-
749- if search_params .get ("from_" ):
750- escaped = escape_imap_string (search_params ["from_" ])
751- criteria_parts .append (f'FROM "{ escaped } "' )
752-
753- if search_params .get ("to" ):
754- for addr in search_params ["to" ]:
755- criteria_parts .append (f'TO "{ addr } "' )
756-
757- if search_params .get ("subject" ):
758- criteria_parts .append (f'SUBJECT "{ search_params ["subject" ]} "' )
759-
760- if search_params .get ("is_read" ) is True :
761- criteria_parts .append ("SEEN" )
762- elif search_params .get ("is_read" ) is False :
763- criteria_parts .append ("UNSEEN" )
764-
765- if search_params .get ("is_flagged" ) is True :
766- criteria_parts .append ("FLAGGED" )
767- elif search_params .get ("is_flagged" ) is False :
768- criteria_parts .append ("UNFLAGGED" )
769-
770- if search_params .get ("has_attachment" ) is True :
771- criteria_parts .append ('HEADER Content-Type "multipart/mixed"' )
772-
773- if search_params .get ("labels" ):
774- for label in search_params ["labels" ]:
775- criteria_parts .append (f'KEYWORD "{ label } "' )
776-
777- if search_params .get ("date_range" ):
778- date_range = search_params ["date_range" ]
779- if date_range .get ("start" ):
780- try :
781- dt = datetime .fromisoformat (date_range ["start" ].replace ("Z" , "+00:00" ))
782- criteria_parts .append (f'SINCE { dt .strftime ("%d-%b-%Y" )} ' )
783- except (ValueError , AttributeError ) as exc :
784- raise RequestException (
785- f"Invalid start date: { date_range ['start' ]} " ,
786- err .ERROR_MAIL_SEARCH_INVALID_DATE
787- ) from exc
788- if date_range .get ("end" ):
789- try :
790- dt = datetime .fromisoformat (date_range ["end" ].replace ("Z" , "+00:00" ))
791- criteria_parts .append (f'BEFORE { dt .strftime ("%d-%b-%Y" )} ' )
792- except (ValueError , AttributeError ) as exc :
793- raise RequestException (
794- f"Invalid end date: { date_range ['end' ]} " ,
795- err .ERROR_MAIL_SEARCH_INVALID_DATE
796- ) from exc
797-
798- criteria = "(" + " " .join (criteria_parts ) + ")" if criteria_parts else "ALL"
740+ # --- Build the protocol-specific search criteria (delegated to the client) ---
741+ criteria = client .build_search_criteria (search_params , include_deleted )
799742
800743 # --- Determine folders to search ---
801744 folder_list = search_params .get ("folders" ) or []
0 commit comments