diff --git a/Packs/EmailCommunication/ReleaseNotes/2_0_12.md b/Packs/EmailCommunication/ReleaseNotes/2_0_12.md new file mode 100644 index 000000000000..f575cc809c9e --- /dev/null +++ b/Packs/EmailCommunication/ReleaseNotes/2_0_12.md @@ -0,0 +1,12 @@ + +#### Scripts + +##### SendEmailReply +- Added support for the *reputation_calc_async* parameter, to prevent timeouts. +- Updated the Docker image to: *demisto/python3:3.10.12.68300*. + + +##### PreprocessEmail + +- Added support for the *reputation_calc_async* parameter, to prevent timeouts. +- Updated the Docker image to: *demisto/python3:3.10.12.68300*. diff --git a/Packs/EmailCommunication/Scripts/PreprocessEmail/PreprocessEmail.py b/Packs/EmailCommunication/Scripts/PreprocessEmail/PreprocessEmail.py index e0a2fde06af9..7ef92e16a55a 100644 --- a/Packs/EmailCommunication/Scripts/PreprocessEmail/PreprocessEmail.py +++ b/Packs/EmailCommunication/Scripts/PreprocessEmail/PreprocessEmail.py @@ -94,14 +94,15 @@ def get_entry_id_list(attachments, files): return entry_id_list -def add_entries(email_reply, email_related_incident): +def add_entries(email_reply, email_related_incident, reputation_calc_async=False): """Add the entries to the related incident Args: email_reply: The email reply. email_related_incident: The related incident. """ entries_str = json.dumps([{"Type": 1, "ContentsFormat": 'html', "Contents": email_reply, "tags": ['email-thread']}]) - res = demisto.executeCommand("addEntries", {"entries": entries_str, 'id': email_related_incident}) + res = demisto.executeCommand("addEntries", {"entries": entries_str, + 'id': email_related_incident, 'reputationCalcAsync': reputation_calc_async}) if is_error(res): demisto.error(ERROR_TEMPLATE.format('addEntries', res['Contents'])) raise DemistoException(ERROR_TEMPLATE.format('addEntries', res['Contents'])) @@ -287,6 +288,7 @@ def get_email_related_incident_id(email_related_incident_code, email_original_su return str(incident.get('id')) except Exception as e: demisto.error(f'Exception while retrieving thread context: {e}') + return None def get_unique_code(): @@ -325,7 +327,7 @@ def create_thread_context(email_code, email_cc, email_bcc, email_text, email_fro incident_id: ID of the related incident attachments: File attachments from the email """ - thread_number = str() + thread_number = '' thread_found = False try: # Get current email threads from context if any are present @@ -380,6 +382,7 @@ def create_thread_context(email_code, email_cc, email_bcc, email_text, email_fro def main(): + args = demisto.args() incident = demisto.incident() attachments = incident.get('attachment', []) custom_fields = incident.get('CustomFields') @@ -394,6 +397,8 @@ def main(): email_replyto = custom_fields.get('emailreplyto', '') email_latest_message = custom_fields.get('emaillatestmessage', '') + reputation_calc_async = argToBoolean(args.get('reputation_calc_async', False)) + try: email_related_incident_code = email_subject.split('<')[1].split('>')[0] email_original_subject = email_subject.split('<')[-1].split('>')[1].strip() @@ -419,7 +424,7 @@ def main(): "Incoming email related to Email Communication Incident" f" {email_related_incident}. Appending a message there.") email_reply = set_email_reply(email_from, email_to, email_cc, html_body, attachments) - add_entries(email_reply, email_related_incident) + add_entries(email_reply, email_related_incident, reputation_calc_async) else: # For all other incident types, add message details as context entry demisto.debug(f"Incoming email related to Incident {email_related_incident}. Appending message there.") diff --git a/Packs/EmailCommunication/Scripts/PreprocessEmail/PreprocessEmail.yml b/Packs/EmailCommunication/Scripts/PreprocessEmail/PreprocessEmail.yml index 206ad224df25..ae3ab2bc2ce8 100644 --- a/Packs/EmailCommunication/Scripts/PreprocessEmail/PreprocessEmail.yml +++ b/Packs/EmailCommunication/Scripts/PreprocessEmail/PreprocessEmail.yml @@ -8,6 +8,13 @@ args: - name: CreateIncidentUntaggedEmail description: Allow the creation of an email for which we can't find an existing incident. defaultValue: 'true' +- name: reputation_calc_async + auto: PREDEFINED + predefined: + - 'true' + - 'false' + description: Specify whether to calculate the reputation in an asynchronous way. + defaultValue: 'false' comment: |- Preprocessing script for email communication layout. This script checks if the incoming email contains an Incident ID to link the mail to an existing incident, and tags the email as "email-thread". @@ -26,7 +33,7 @@ tags: - email - preProcessing type: python -dockerimage: demisto/python3:3.10.12.63474 +dockerimage: demisto/python3:3.10.12.68300 runas: DBotRole tests: - No tests (auto formatted) diff --git a/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.py b/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.py index 3780b8379db6..73e3c40ca0be 100644 --- a/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.py +++ b/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.py @@ -157,7 +157,7 @@ def create_thread_context(email_code, email_cc, email_bcc, email_text, email_fro incident_id: ID of the related incident new_attachment_names: File attachments sent with the email """ - thread_number = str() + thread_number = '' thread_found = False try: incident_email_threads = get_email_threads(incident_id) @@ -403,7 +403,7 @@ def create_file_data_json(attachment, field_name): return json.dumps(file_data) -def get_reply_body(notes, incident_id, attachments): +def get_reply_body(notes, incident_id, attachments, reputation_calc_async=False): """ Get the notes and the incident id and return the reply body Args: notes (list): The notes of the email. @@ -429,7 +429,8 @@ def get_reply_body(notes, incident_id, attachments): entry_note = json.dumps( [{"Type": 1, "ContentsFormat": 'html', "Contents": reply_body, "tags": ['email-thread']}]) - entry_tags_res = demisto.executeCommand("addEntries", {"entries": entry_note, 'id': incident_id}) + entry_tags_res = demisto.executeCommand( + "addEntries", {"entries": entry_note, 'id': incident_id, 'reputationCalcAsync': reputation_calc_async}) entry_note_res = demisto.executeCommand("demisto-api-post", {"uri": "/entry/note", "body": json.dumps( {"id": note.get('ID'), "version": -1, "investigationId": incident_id, "data": "false"})}) @@ -613,6 +614,7 @@ def resend_first_contact(email_selected_thread, email_thread, incident_id, new_e else: return_error(f'The selected Thread Number to respond to ({email_selected_thread}) ' f'does not exist. Please choose a valid Thread Number and re-try.') + return None def format_body(new_email_body): @@ -633,7 +635,7 @@ def format_body(new_email_body): def single_thread_reply(email_code, incident_id, email_cc, add_cc, notes, attachments, files, email_subject, subject_include_incident_id, email_to_str, service_mail, email_latest_message, - mail_sender_instance): + mail_sender_instance, reputation_calc_async=False): """ Retrieve all entries in the EmailThreads context key Args: @@ -662,7 +664,7 @@ def single_thread_reply(email_code, incident_id, email_cc, add_cc, notes, attach 'customFields': {'emailgeneratedcode': email_code}}) try: final_email_cc = get_email_cc(email_cc, add_cc) - reply_body, reply_html_body = get_reply_body(notes, incident_id, attachments) + reply_body, reply_html_body = get_reply_body(notes, incident_id, attachments, reputation_calc_async) entry_id_list = get_entry_id_list(incident_id, attachments, [], files) result = validate_email_sent(incident_id, email_subject, subject_include_incident_id, email_to_str, reply_body, service_mail, final_email_cc, '', reply_html_body, entry_id_list, @@ -748,13 +750,13 @@ def collect_thread_details(incident_email_threads, email_selected_thread): Tuple containing details of the selected email thread for re-use in creating reply message """ thread_found = False - reply_to_message_id = str() - reply_recipients = str() - reply_subject = str() - reply_mailbox = str() - thread_cc = str() - thread_bcc = str() - reply_code = str() + reply_to_message_id = '' + reply_recipients = '' + reply_subject = '' + reply_mailbox = '' + thread_cc = '' + thread_bcc = '' + reply_code = '' outbound_only = True last_thread_processed = 0 @@ -973,6 +975,8 @@ def main(): email_selected_thread = custom_fields.get('emailselectedthread') subject_include_incident_id = argToBoolean(args.get('subject_include_incident_id', False)) + argToBoolean(args.get('reputation_calc_async', False)) + if new_email_attachments: new_attachment_names = ', '.join([attachment.get('name', '') for attachment in new_email_attachments]) else: @@ -982,7 +986,7 @@ def main(): # This case is run when replying to an email from the 'Email Communication' layout single_thread_reply(email_code, incident_id, email_cc, add_cc, notes, attachments, files, email_subject, subject_include_incident_id, email_to_str, service_mail, email_latest_message, - mail_sender_instance) + mail_sender_instance, reputation_calc_async=False) elif new_thread == 'true': # This case is run when using the 'Email Threads' layout to send a new first-contact email message diff --git a/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.yml b/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.yml index 1053eaff6d8e..3258519738cf 100644 --- a/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.yml +++ b/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.yml @@ -24,6 +24,13 @@ args: - name: subject_include_incident_id description: Include the Incident ID within the email subject. defaultValue: 'false' +- name: reputation_calc_async + auto: PREDEFINED + predefined: + - 'true' + - 'false' + description: Specify whether to calculate the reputation in an asynchronous way. + defaultValue: 'false' comment: |- Send email reply This automation runs using the default Limited User role, unless you explicitly change the permissions. @@ -39,7 +46,7 @@ subtype: python3 system: true type: python fromversion: 5.0.0 -dockerimage: demisto/python3:3.10.12.63474 +dockerimage: demisto/python3:3.10.12.68300 tests: - No tests (auto formatted) contentitemexportablefields: diff --git a/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply_test.py b/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply_test.py index 3af89ec974a7..f73b07aae82d 100644 --- a/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply_test.py +++ b/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply_test.py @@ -5,12 +5,12 @@ def util_open_file(path): - with open(path, mode='r') as f: + with open(path) as f: return f.read() def util_load_json(path): - with open(path, mode='r') as f: + with open(path) as f: return json.loads(f.read()) @@ -531,7 +531,7 @@ def test_single_thread_reply(email_code, mocker): - Validate that if no email_code is provided, 'get_unique_code' is called to generate one """ - def get_reply_body_side_effect(notes, incident_id, attachments): # noqa + def get_reply_body_side_effect(notes, incident_id, attachments, reputation_calc_async): # noqa return 'Email body.', 'Email body.' from SendEmailReply import single_thread_reply diff --git a/Packs/EmailCommunication/pack_metadata.json b/Packs/EmailCommunication/pack_metadata.json index 9f7918301747..d34a39203c2c 100644 --- a/Packs/EmailCommunication/pack_metadata.json +++ b/Packs/EmailCommunication/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Email Communication", "description": "Do you have to send multiple emails to end users? This content pack helps you streamline the process and automate updates, notifications and more.\n", "support": "xsoar", - "currentVersion": "2.0.11", + "currentVersion": "2.0.12", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "videos": [