Symantec Email Security Cloud

Symantec Email Security.cloud is a hosted service that filters email messages and helps protect organizations from malware (including targeted attacks and phishing), spam, and unwanted bulk email. The service offers encryption and data protection options to help control sensitive information sent by email and supports multiple mailbox types from various vendors.

Email · SymantecEmailSecurity

Details

IDSymantec Email Security Cloud
ProviderBroadcom
CategoryEmail
From Version5.0.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

Symantec Email Security.cloud is a hosted service that filters email messages and helps protect organizations from malware (including targeted attacks and phishing), spam, and unwanted bulk email. The service offers encryption and data protection options to help control sensitive information sent by email and supports multiple mailbox types from various vendors.
This integration was integrated and tested with version 10.6.6 of Symantec Email Security Cloud.

Use cases

  1. IOC Management: Manage IOCs for email threats across domains: list, add, update, delete, or renew IOCs.
  2. Data Feeds: Retrieve threat data (e.g., malware, spam, clicks) for insights into email security events.
  3. Email Queue Monitoring: View queue statistics per domain to monitor email processing and delays.
  4. Quarantine Actions: List, preview, release, or delete quarantined emails to manage potentially harmful content.
  5. Allow and Block Lists: Maintain lists for permitted or restricted senders/domains: retrieve, add/update, or delete items.
  6. Fetch Incidents: Auto-fetch incidents and quarantine-specific threats to streamline response and compliance.

Configure Symantec Email Security Cloud on Cortex XSOAR

  1. Navigate to Settings > Integrations > Servers & Services.
  2. Search for Symantec Email Security Cloud.
  3. Click Add instance to create and configure a new integration instance.

    Parameter Description Required
    Server URL - IOC    
    Server URL - Data Feeds    
    Server URL - Email Queue    
    Server URL - Quarantine The Quarantine API is available for the United States (us) and European Union (eu).  
    Username Relevant to: Server URL - IOC, Server URL - Email Queue, Server URL - Quarantine False
    Password   False
    Quarantine Username Relevant to: Server URL - Quarantine False
    Password   False
    Use system proxy settings    
    Trust any certificate (not secure)    
    Fetch incidents    
    Incident type    
    Maximum number of incidents per fetch Maximum number of incidents per fetch. Default is 50. The maximum is 200.  
    First Fetch Time    
    Fetch Type The API to fetch incidents from: Data Feeds, Quarantine or both.  
    Severity - Email Data Feed Filter the incidents by their severity. When left empty will fetch all.  
    Type - Email Data Feed    
    Include Delivery - Email Data Feed Only relevant to `all` feed. Contains metadata that describes both inbound and outbound email delivery to provide visibility into email tracing, TLS compliance, and routing.  
    Query - Email Quarantine A search criterion that can be used to filter emails that match only certain conditions based on email metadata.  
    Type - Email Quarantine A string used to filter emails based on the quarantine type.  
    Admin Domain - mail Quarantine Returns the emails quarantined for users in a particular domain. If this parameter is present and has a valid domain name, then items from only that domain are returned. If it has a value of `ALL`, then all domains administered by the user are searched and emails quarantined for users in those domains are returned. Note: Can only be used by an administrator user.  
  4. Click Test to validate the URLs, token, and connection.

Commands

You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

symantec-email-security-ioc-list


List the IOCs that apply to a specific domain or to all domains.

Base Command

symantec-email-security-ioc-list

Input

Argument Name Description Required
domain Run the command for a specific domain, for all domains use ‘global’. Run symantec-email-security-email-queue-list to get a list of available domains. Default is global. Optional
limit The maximum number of records to return. Default is 50. Optional
all_results Whether to retrieve all the results by overriding the default limit. Possible values are: true, false. Optional

Context Output

Path Type Description
SymantecEmailSecurity.IOC.iocBlackListId String ID of the IOC.
SymantecEmailSecurity.IOC.iocType String Type of the IOC value.
SymantecEmailSecurity.IOC.iocValue String Value of the IOC.
SymantecEmailSecurity.IOC.status String Whether the IOC is active.
SymantecEmailSecurity.IOC.description String Description of the IOC.
SymantecEmailSecurity.IOC.emailDirection String Email direction. Can be one of: I=Inbound, O=Outbound or B=Both.
SymantecEmailSecurity.IOC.remediationAction String Remediation Action. Can be one of: B=Block and delete, Q=Quarantine, M=Redirect, T=Tag subject or H=Append header.
SymantecEmailSecurity.IOC.expiryDate String Retention period for an IOC until it is removed from the system.

Command example

Human Readable Output

IOC(s)

ID Type Value Status Description Email Direction Remediation Action Expiry Date
00000000-0000-0000-0000-000000000000 subject Test Active Test inbound quarantine 2024-01-01 00:00:00.0
00000000-0000-0000-0000-000000000000 url https://www.example.com Active url to block outbound append header 2024-01-01 00:00:00.0

symantec-email-security-ioc-action


Add, update, delete, and renew multiple IOCs through the entry_id or a single IOC through the rest of the parameters.

Base Command

symantec-email-security-ioc-action

Input

Argument Name Description Required
domain Run the command for a specific domain, for all domains use ‘global’. Run symantec-email-security-email-queue-list to get a list of available domains. Default is global. Optional
action Defines the action for IOCs: ‘merge’ to merge or update IOCs in the database by their type and value without inputting ioc_id; ‘replace’ to delete and replace all IOCs in the database without inputting upload_ioc_json; ‘ioc’ to add, update, delete, or renew multiple IOCs each with their own action, use this only when entering an entry_id; ‘add’ to add an IOC without inputting ioc_id. Possible values are: merge, replace, upload_ioc_json, add, update, delete, renew. Required
entry_id Entry ID of a JSON file to pass multiple IOCs. Only accepts action=merge/replace/ioc. Example value: [{“APIRowAction”: “U”, “IocBlacklistId”: xxxx, “IocType”: “url”, “IocValue”: “https://www.example.com”, “Description”: “Hello World!”}]. More about IOCs can be found in: https://techdocs.broadcom.com/content/dam/broadcom/techdocs/us/en/dita/symantec-security-software/email-security/email-security-cloud/content/Indicators-of-Compromise-(IOC)-Blacklist-API-Guide.pdf. Optional
ioc_id ID of the IOC. Can’t be used with action=merge\replace`add`. Optional
ioc_type Type of the IOC. Possible values are: attachmentname, md5attachment, sha2attachment, bodysenderdomain, bodysenderemail, bodysendertopleveldomain, envelopesenderdomain, envelopesenderemail, envelopesendertopleveldomain, senderipaddress, senderiprange, recipientdomain, recipientemail, subject, url. Optional
ioc_value Value of the IOC. Optional
description Description of the IOC. Optional
email_direction Email direction to filter IOCs. Possible values are: inbound, outbound, both. Optional
remediation_action Remediation action to be done on an IOC. Possible values are: block_and_delete, quarantine, redirect, tag_subject, append_header. Optional

Context Output

There is no context output for this command.

Command example

!symantec-email-security-ioc-action action=add ioc_type=subject ioc_value=Test123 description=test email_direction=inbound remediation_action=block_and_delete

Human Readable Output

All IOC(s) were uploaded successfully

symantec-email-security-ioc-renew


Renew all IOCs previously uploaded and still in the database, whether active or inactive, for a specific domain or all domains. The default retention period for IOCs is 7 days and the maximum is 30 days. After 30 days IOCs are retained in an inactive state for another 14 days. If an organization receives new email containing previously block listed IOCs, then the IOCs can renewed in the block list within this grace period. Thereafter, IOCs are removed from the system and must be uploaded again to remain in the block list.

Base Command

symantec-email-security-ioc-renew

Input

Argument Name Description Required
domain Run the command for a specific domain, for all domains use ‘global’. Run symantec-email-security-email-queue-list to get a list of available domains. Default is global. Optional

Context Output

There is no context output for this command.

Command example

Human Readable Output

Email Data Feed(s)

Message Size Subject Envelope From Envelope To Sender IP Sender Mail Server File/URLs With Risk Incidents
10000 New Email Quarantine Account bounce-newaccount-verp-00000000000000000000@eu.quarantine.symantec.com hello@world 0.0.0.0 0.0.0.0.googleusercontent.com Unknown00000000.data-None,
https://www.example.com-1
{‘Severity’: ‘LOW’, ‘Security Service’: ‘Anti-Malware’, ‘Detection Method’: ‘Skeptic Heuristics’, ‘Verdict’: ‘Malware’, ‘Action’: ‘Block’}

symantec-email-security-email-queue-list


Returns a list of domains owned by the customer, with queue statistics for each domain.

Base Command

symantec-email-security-email-queue-list

Input

Argument Name Description Required
domains Comma-separated list of domains to retrieve. Leave empty to retrieve all domains. Optional
limit The maximum number of records to return. Default is 50. Optional
all_results Whether to retrieve all the results by overriding the default limit. Possible values are: true, false. Optional

Context Output

Path Type Description
SymantecEmailSecurity.EmailQueue.TotalMessagesInbound Number Total number of inbound messages in the queue, for all domains.
SymantecEmailSecurity.EmailQueue.TotalMessagesOutbound Number Total number of outbound messages in the queue, for all domains.
SymantecEmailSecurity.EmailQueue.MeanTimeInQueueInbound Number Average (mean) queue wait for inbound messages, for all domains. Measured in seconds.
SymantecEmailSecurity.EmailQueue.MeanTimeInQueueOutbound Number Average (mean) queue wait for outbound messages, for all domains. Measured in seconds.
SymantecEmailSecurity.EmailQueue.LongestTimeInInbound Number How long the oldest message in the inbound queue has been queued, across all domains. Measured in seconds.
SymantecEmailSecurity.EmailQueue.LongestTimeInOutbound Number How long the oldest message in the outbound queue has been queued, across all domains. Measured in seconds.
SymantecEmailSecurity.EmailQueue.Domains.Name String Name of the domain.
SymantecEmailSecurity.EmailQueue.Domains.ReceiveQueueCountInbound Number Number of inbound messages waiting to be processed.
SymantecEmailSecurity.EmailQueue.Domains.ReceiveQueueCountOutbound Number Number of outbound messages waiting to be processed.
SymantecEmailSecurity.EmailQueue.Domains.DeliveryQueueCountInbound Number Number of inbound messages that have been processed and are waiting to be delivered.
SymantecEmailSecurity.EmailQueue.Domains.DeliveryQueueCountOutbound Number Number of outbound messages that have been processed and are waiting to be delivered.
SymantecEmailSecurity.EmailQueue.Domains.LongestTimeInReceiveQueueInbound Number Oldest inbound message in the queue waiting to be processed. Measured in seconds.
SymantecEmailSecurity.EmailQueue.Domains.LongestTimeInReceiveQueueOutbound Number Oldest outbound message in the queue waiting to be processed. Measured in seconds.
SymantecEmailSecurity.EmailQueue.Domains.LongestTimeInDeliveryQueueInbound Number Oldest inbound message waiting to be delivered after processing. Measured in seconds.
SymantecEmailSecurity.EmailQueue.Domains.LongestTimeInDeliveryQueueOutbound Number Oldest outbound message waiting to be delivered after processing. Measured in seconds.
SymantecEmailSecurity.EmailQueue.Domains.MeanTimeInReceiveQueueInbound Number Average (mean) wait time for inbound messages waiting to be processed. Measured in seconds.
SymantecEmailSecurity.EmailQueue.Domains.MeanTimeInReceiveQueueOutbound Number Average (mean) wait time for outbound messages waiting to be processed. Measured in seconds.
SymantecEmailSecurity.EmailQueue.Domains.MeanTimeInDeliveryQueueInbound Number Average (mean) wait time for inbound messages waiting to be delivered after processing. Measured in seconds.
SymantecEmailSecurity.EmailQueue.Domains.MeanTimeInDeliveryQueueOutbound Number Average (mean) wait time for outbound messages waiting to be delivered after processing. Measured in seconds.

Command example

Human Readable Output

Email Queue Statistic(s)

Totalmessagesinbound Totalmessagesoutbound Meantimeinqueueinbound Meantimeinqueueoutbound Longesttimeininbound Longesttimeinoutbound
0 0 0 0 0 0

Domain Statistic(s)

Name Receivequeuecountinbound Receivequeuecountoutbound Deliveryqueuecountinbound Deliveryqueuecountoutbound
lior.sb 0 0 0 0

symantec-email-security-quarantine-email-list


Retrieves the metadata for quarantined emails belonging to the authenticated user. If the user is an administrator, the API provides options to retrieve the metadata for emails quarantined for another user under his administration.

Base Command

symantec-email-security-quarantine-email-list

Input

Argument Name Description Required
q A search criterion that can be used to filter emails that match only certain conditions based on email metadata. The search syntax is built by a field name and search value enclosed by parenthesis and the operators: ‘OR’, ‘AND’ to combine multiple search criteria’s or values, example: (email_subject:test). Acceptable field names are: ‘dlp_message_id’, ‘email_envelope_sender’, ‘email_envelope_sender.raw’, ‘email_sender’, ‘email_envelope_recipient’, ‘email_envelope_recipient.raw’, ‘email_subject’, ‘email_subject.raw’. See the section called “Search String Syntax” on page 16 in: https://techdocs.broadcom.com/content/dam/broadcom/techdocs/us/en/dita/symantec-security-software/email-security/email-security-cloud/content/EmailQuarantineAPIGuide.pdf. Optional
sort_column Specifies the column to use for sorting. Defaults to email_date_received. Optional
sort_order Specifies the order in which to sort. Possible values are: desc, asc. Default is desc. Optional
after A time stamp value used to select only SUDULS items that were created after this time. Accepted formats: any substring of yyyy-mm-ddThh:mm:ssZ, epoch 1720617001, relative 1 day 2h 3 minute. Optional
before A time stamp value used to select only SUDULS items that were created before this time. Accepted formats: any substring of yyyy-mm-ddThh:mm:ssZ, epoch 1720617001, relative 1 day 2h 3 minute. Optional
filter_type A string used to filter emails based on the quarantine type. By default includes the emails quarantined for all types. COMPLIANCE: Includes Content control, DLP and Image control emails. DLP: Includes only DLP emails. Possible values are: SPAM, NEWSLETTER, CI, CO, II, IO, COMPLIANCE, DLP. Optional
include_deleted Specifies whether to include items marked as deleted in the search results. Possible values are: true, false. Optional
user_email Return only the quarantined emails of the user whose email address is specified. Note: Can only be used by an administrator user. Optional
admin_domain Returns the emails quarantined for users in a particular domain. If this parameter is present and has a valid domain name, then items from only that domain are returned. If it has a value of ALL, then all domains administered by the user are searched and emails quarantined for users in those domains are returned. Note: Can only be used by an administrator user. Optional
limit The maximum number of records to return. Default is 50. Optional
page The page number to retrieve records from. Optional
page_size The maximum number of records to return per page. Default is 50. Max is 10,000. Optional

Context Output

Path Type Description
SymantecEmailSecurity.QuarantineEmail.id String ID of the item.
SymantecEmailSecurity.QuarantineEmail.metadata.email_date_received Date Date the email was received.
SymantecEmailSecurity.QuarantineEmail.metadata.quarantine_info.direction String Direction of the email.
SymantecEmailSecurity.QuarantineEmail.metadata.quarantine_info.quarantine_type String Quarantine type of the email, can be one of: SPAM, NEWSLETTER, CI, CO, II, IO, COMPLIANCE, DLP.
SymantecEmailSecurity.QuarantineEmail.metadata.email_is_viewed Bool Whether the email was viewed.
SymantecEmailSecurity.QuarantineEmail.metadata.email_is_released Bool Whether the email was released.
SymantecEmailSecurity.QuarantineEmail.metadata.quarantine_reason String Reason why the email was quarantined.
SymantecEmailSecurity.QuarantineEmail.metadata.email_sender String Sender of the email.
SymantecEmailSecurity.QuarantineEmail.metadata.service_type String Service type used for the email.
SymantecEmailSecurity.QuarantineEmail.metadata.master_recipient String Recipient of the email.
SymantecEmailSecurity.QuarantineEmail.metadata.user_id Number ID of the user.
SymantecEmailSecurity.QuarantineEmail.metadata.email_envelope_sender String Address to respond to in case of bounce messages or errors.
SymantecEmailSecurity.QuarantineEmail.metadata.email_subject String Subject of the email.
SymantecEmailSecurity.QuarantineEmail.metadata.email_size Number Size of the email.
SymantecEmailSecurity.QuarantineEmail.metadata.email_envelope_recipient String The RCPT TO address.
SymantecEmailSecurity.QuarantineEmail.actions.view_subject Bool Whether the subject can be viewed.
SymantecEmailSecurity.QuarantineEmail.actions.delete_message Bool Whether the email can be deleted.
SymantecEmailSecurity.QuarantineEmail.actions.preview_message Bool Whether the email can be previewed.
SymantecEmailSecurity.QuarantineEmail.actions.release_message Bool Whether the email can be released.

Command example

Human Readable Output

Quarantine Email(s)

ID Date Received Direction Quarantine Type Is Released Quarantine Reason Sender Master Recipient Subject
000 2024-10-06 09:20:41.148000+00:00 inbound CI true CC Example (example@example.com) example@example.com a
001 2024-10-06 13:37:51.295000+00:00 inbound CI false CC Example (example@example.com) example@example.com a
002 2024-10-06 13:37:55.373000+00:00 inbound CI false CC Example (example@example.com) example@example.com a
003 2024-10-06 13:38:00.677000+00:00 inbound CI true CC Example (example@example.com) example@example.com a
004 2024-10-06 13:40:11.087000+00:00 inbound CI false CC Example (example@example.com) example@example.com a

symantec-email-security-quarantine-email-preview


Retrieves the contents of the email specified in the request. To preview an email the compliance policy must allow it.

Base Command

symantec-email-security-quarantine-email-preview

Input

Argument Name Description Required
message_id The message ID of the email to preview. Run symantec-email-security-email-queue-list to get a list of message IDs. Required

Context Output

Path Type Description
SymantecEmailSecurity.QuarantineEmailPreview.message_id String ID of the message.
SymantecEmailSecurity.QuarantineEmailPreview.headers.authentication-results String Authentication status of the email.
SymantecEmailSecurity.QuarantineEmailPreview.headers.content-type String The MIME type of the email content, defining how the content is structured.
SymantecEmailSecurity.QuarantineEmailPreview.headers.date Date The date and time when the email was sent.
SymantecEmailSecurity.QuarantineEmailPreview.headers.dkim-signature String The DKIM signature used to verify the authenticity of the email.
SymantecEmailSecurity.QuarantineEmailPreview.headers.feedback-id String A unique identifier used for tracking feedback and reporting issues related to the email.
SymantecEmailSecurity.QuarantineEmailPreview.headers.from String The sender’s email address and name.
SymantecEmailSecurity.QuarantineEmailPreview.headers.mailfrom String The envelope sender email address.
SymantecEmailSecurity.QuarantineEmailPreview.headers.message-id String Unique identifier for the email message.
SymantecEmailSecurity.QuarantineEmailPreview.headers.mime-version String The MIME version used for the email.
SymantecEmailSecurity.QuarantineEmailPreview.headers.received String Information about the servers the email passed through.
SymantecEmailSecurity.QuarantineEmailPreview.headers.reply-to String The email address where replies to the message should be sent.
SymantecEmailSecurity.QuarantineEmailPreview.headers.subject String The subject line of the email.
SymantecEmailSecurity.QuarantineEmailPreview.headers.to String The recipient’s email address.
SymantecEmailSecurity.QuarantineEmailPreview.headers.x-brightmail-tracker String Tracking data for Brightmail filtering.
SymantecEmailSecurity.QuarantineEmailPreview.headers.x-originating-ip String IP address of the original sender.
SymantecEmailSecurity.QuarantineEmailPreview.attachments.name String The name of the file attached to the email.
SymantecEmailSecurity.QuarantineEmailPreview.attachments.type String The type of the file attached to the email.
SymantecEmailSecurity.QuarantineEmailPreview.bodypart.type String The type of the email’s body part.
SymantecEmailSecurity.QuarantineEmailPreview.bodypart.content String The content of the email’s body part.

Command example

!symantec-email-security-quarantine-email-preview message_id=000

Context Example

{
    "SymantecEmailSecurity": {
        "QuarantineEmailPreview": {
            "attachments": [
                {
                    "name": "hello",
                    "type": "world"
                }
            ],
            "bodypart": [
                {
                    "content": "xxx",
                    "type": "text/plain; charset=\"UTF-8\""
                },
                {
                    "content": "xxx",
                    "type": "text/html; charset=\"UTF-8\""
                }
            ],
            "headers": {
                "authentication-results": "xxx",
                "content-type": "multipart/alternative;",
                "date": "Wed, 02 Oct 2024 04:37:01 +0000",
                "dkim-signature": "v=1; a=rsa-sha256;",
                "feedback-id": "xxx",
                "from": "xxx",
                "mailfrom": "example@example.com",
                "message-id": "123",
                "mime-version": "1.0",
                "received": "xxx",
                "reply-to": "xxx",
                "subject": "xxx",
                "to": "xxx",
                "x-atlassian-mail-message-id": "xxx",
                "x-atlassian-mail-transaction-id": "xxx",
                "x-brightmail-tracker": "xxx",
                "x-msfbl": "xxx",
                "x-originating-ip": "[0.0.0.0]",
                "x-spamquarantineinfo": "spam detected heuristically",
                "x-spamquarantinereason": "Yes, hits=1.2 required=7.0 tests=newsletters: ,  newsletters: Newsletter detected: 5.12 >"
            },
            "message_id": "000"
        }
    }
}

Human Readable Output

Quarantine Email Preview

Date From To Subject
Wed, 02 Oct 2024 04:37:01 +0000 xxx xxx xxx

Attachments

Name Type
hello world

Body Parts

Content
xxx
xxx

symantec-email-security-quarantine-email-release


Releases the set of quarantined emails specified in the request.

Base Command

symantec-email-security-quarantine-email-release

Input

Argument Name Description Required
message_ids Comma-separated list of emails message IDs to release. Run symantec-email-security-quarantine-email-list to get a list of message IDs. Required
recipient An email address to which the mails have to be released instead of the recipient user’s address. Optional
headers Comma-separated list of x-headers that will be added to the message on release. Optional
encrypt If true adds an ‘x-encrypted-quarantine-release: true’ to the released email. Customers have to configure a corresponding DP rule that triggers encryption. Possible values are: true, false. Optional

Context Output

There is no context output for this command.

Command example

!symantec-email-security-quarantine-email-release message_ids=000

Human Readable Output

Successfully released all messages

symantec-email-security-quarantine-email-delete


Deletes the set of quarantined emails specified in the request. The items are marked as deleted in the backend data store, but are not physically deleted.

Base Command

symantec-email-security-quarantine-email-delete

Input

Argument Name Description Required
message_ids Comma-separated list of quarantined emails message IDs to delete. Run symantec-email-security-quarantine-email-list to get a list of message IDs. Required

Context Output

There is no context output for this command.

Command example

!symantec-email-security-quarantine-email-delete message_ids=000

Human Readable Output

Successfully deleted all messages

symantec-email-security-item-allow-list


Retrieve the allow list items.

Base Command

symantec-email-security-item-allow-list

Input

Argument Name Description Required
q A string that at least some part of the allow list item must contain. Optional
sort_column Specifies the column to use for sorting. Possible values are: date, type, description. Default is date. Optional
sort_order Specifies the order in which to sort. Possible values are: desc, asc. Default is desc. Optional
after A time stamp value used to select only SUDULS items that were created after this time. Accepted formats: any substring of yyyy-mm-ddThh:mm:ssZ, epoch 1720617001, relative 1 day 2h 3 minute. Optional
before A time stamp value used to select only SUDULS items that were created before this time. Accepted formats: any substring of yyyy-mm-ddThh:mm:ssZ, epoch 1720617001, relative 1 day 2h 3 minute. Optional
limit The maximum number of records to return. Default is 50. Optional
page The page number to retrieve records from. Optional
page_size The maximum number of records to return per page. Default is 50. Optional

Context Output

Path Type Description
SymantecEmailSecurity.AllowList.id String ID of the item.
SymantecEmailSecurity.AllowList.value String An email address or a domain name.
SymantecEmailSecurity.AllowList.description String Description of the item.
SymantecEmailSecurity.AllowList.type String Email or domain.
SymantecEmailSecurity.AllowList.date_created Date Date at which the item was created.
SymantecEmailSecurity.AllowList.date_amended Date Date at which the item was amended.

Command example

Human Readable Output

Allow List Item(s)

Description
Test
url to block

symantec-email-security-item-allow-list-update


Allows a SUDULS (allow quarantine users to maintain their own lists of email addresses or domains) user to add or update an item to the allow list.

Base Command

symantec-email-security-item-allow-list-update

Input

Argument Name Description Required
suduls_user Email address of the user for whom the entry should be added in the allow list. Required
item_id ID of SUDULS item to be added/updated. Only required when updating an existing item. Run symantec-email-security-item-allow-list to get a list of items. Optional
email_or_domain Email address or domain to be added in the allow list. Required
description Description of the item to be added to the allow list. Required

Context Output

There is no context output for this command.

Command example

!symantec-email-security-item-allow-list-update suduls_user=lior description=sb email_or_domain=lior.sb item_id=000

Human Readable Output

The items were successfully merged

symantec-email-security-item-allow-list-delete


Allows a SUDULS (allow quarantine users to maintain their own lists of email addresses or domains) user to delete an item from the allow list.

Base Command

symantec-email-security-item-allow-list-delete

Input

Argument Name Description Required
item_id ID of SUDULS item to be deleted. Run symantec-email-security-item-allow-list to get a list of items. Required

Context Output

There is no context output for this command.

Command example

!symantec-email-security-item-allow-list-delete item_id=000

Human Readable Output

The items were successfully deleted

symantec-email-security-item-block-list


Retrieve the block list items.

Base Command

symantec-email-security-item-block-list

Input

Argument Name Description Required
q A string that at least some part of the block list item must contain. Optional
sort_column Specifies the column to use for sorting. Default is date. Optional
sort_order Specifies the order in which to sort. Default is desc. Optional
after A time stamp value used to select only SUDULS items that were created after this time. Accepted formats: any substring of yyyy-mm-ddThh:mm:ssZ, epoch 1720617001, relative 1 day 2h 3 minute. Optional
before A time stamp value used to select only SUDULS items that were created before this time. Accepted formats: any substring of yyyy-mm-ddThh:mm:ssZ, epoch 1720617001, relative 1 day 2h 3 minute. Optional
limit The maximum number of records to return. Default is 50. Optional
page The page number to retrieve records from. Optional
page_size The maximum number of records to return per page. Default is 50. Optional

Context Output

Path Type Description
SymantecEmailSecurity.BlockList.id String ID of the item.
SymantecEmailSecurity.BlockList.value String An email address or a domain name.
SymantecEmailSecurity.BlockList.description String Description of the item.
SymantecEmailSecurity.BlockList.type String Email or domain.
SymantecEmailSecurity.BlockList.date_created Date Date at which the item was created.
SymantecEmailSecurity.BlockList.date_amended Date Date at which the item was amended.

Command example

Human Readable Output

Block List Item(s)

Description
Test
url to block

symantec-email-security-item-block-list-update


Allows a SUDULS (allow quarantine users to maintain their own lists of email addresses or domains) user to add or update an item to the block list.

Base Command

symantec-email-security-item-block-list-update

Input

Argument Name Description Required
suduls_user Email address of the user for whom the entry should be added in the block list. Required
item_id ID of SUDULS item to be added/updated. Only required when updating an existing item. Run symantec-email-security-item-block-list to get a list of items. Optional
email_or_domain Email address or domain to be added to the block list. Required
description Description of the item to be added to the block list. Required

Context Output

There is no context output for this command.

Command example

!symantec-email-security-item-block-list-update suduls_user=lior description=sb email_or_domain=lior.sb item_id=000

Human Readable Output

The items were successfully merged

symantec-email-security-item-block-list-delete


Allows a SUDULS (allow quarantine users to maintain their own lists of email addresses or domains) user to delete an item from the block list.

Base Command

symantec-email-security-item-block-list-delete

Input

Argument Name Description Required
item_id ID of SUDULS item to be deleted. Run symantec-email-security-item-block-list to get a list of items. Required

Context Output

There is no context output for this command.

Command example

!symantec-email-security-item-block-list-delete item_id=000

Human Readable Output

The items were successfully deleted

Configuration parameters

  • url_ioc — Server URL - IOC
  • url_data_feeds — Server URL - Data Feeds
  • url_email_queue — Server URL - Email Queue
  • url_quarantine — Server URL - Quarantine
  • credentials — Username
  • quarantine_credentials — Quarantine Username
  • proxy — Use system proxy settings
  • insecure — Trust any certificate (not secure)
  • isFetch — Fetch incidents
  • incidentType — Incident type
  • incidentFetchInterval — Incidents Fetch Interval
  • max_fetch — Maximum number of incidents per fetch
  • first_fetch — First Fetch Time
  • fetch_type — Fetch Type
  • severity — Severity - Email Data Feed
  • type — Type - Email Data Feed
  • include_delivery — Include Delivery - Email Data Feed
  • query_quarantine — Query - Email Quarantine
  • type_quarantine — Type - Email Quarantine
  • admin_domain_quarantine — Admin Domain - mail Quarantine

Commands (15)

  • symantec-email-security-data-list

    Retrieves data feeds from Symantec Email Security.cloud. Available feeds: 'all' (metadata for all scanned email), 'malware' (malware-containing email data), 'threat-isolation' (events from URL and Attachment Isolation), 'clicktime' (metadata from end-user clicks on rewritten URLs), 'anti-spam' (spam detection metadata), and 'ec-reports' (contextual information about emails blocked by Anti-Malware service).

  • symantec-email-security-email-queue-list

    Returns a list of domains owned by the customer, with queue statistics for each domain.

  • symantec-email-security-ioc-action

    Add, update, delete, and renew multiple IOCs through the `entry_id` or a single IOC through the rest of the parameters.

  • symantec-email-security-ioc-list

    List the IOCs that apply to a specific domain or to all domains.

  • symantec-email-security-ioc-renew

    Renew all IOCs previously uploaded and still in the database, whether active or inactive, for a specific domain or all domains. The default retention period for IOCs is 7 days and the maximum is 30 days. After 30 days IOCs are retained in an inactive state for another 14 days. If an organization receives new email containing previously block listed IOCs, then the IOCs can renewed in the block list within this grace period. Thereafter, IOCs are removed from the system and must be uploaded again to remain in the block list.

  • symantec-email-security-item-allow-list

    Retrieve the allow list items.

  • symantec-email-security-item-allow-list-delete

    Allows a SUDULS (allow quarantine users to maintain their own lists of email addresses or domains) user to delete an item from the allow list.

  • symantec-email-security-item-allow-list-update

    Allows a SUDULS (allow quarantine users to maintain their own lists of email addresses or domains) user to add or update an item to the allow list.

  • symantec-email-security-item-block-list

    Retrieve the block list items.

  • symantec-email-security-item-block-list-delete

    Allows a SUDULS (allow quarantine users to maintain their own lists of email addresses or domains) user to delete an item from the block list.

  • symantec-email-security-item-block-list-update

    Allows a SUDULS (allow quarantine users to maintain their own lists of email addresses or domains) user to add or update an item to the block list.

  • symantec-email-security-quarantine-email-delete

    Deletes the set of quarantined emails specified in the request. The items are marked as deleted in the backend data store, but are not physically deleted.

  • symantec-email-security-quarantine-email-list

    Retrieves the metadata for quarantined emails belonging to the authenticated user. If the user is an administrator, the API provides options to retrieve the metadata for emails quarantined for another user under his administration.

  • symantec-email-security-quarantine-email-preview

    Retrieves the contents of the email specified in the request. To preview an email the compliance policy must allow it.

  • symantec-email-security-quarantine-email-release

    Releases the set of quarantined emails specified in the request.

import copy
import json
import os
import unittest.mock
from collections.abc import Callable
from datetime import datetime
from typing import Any

import CommonServerPython
import pytest
import SymantecEmailSecurity

TEST_DATA = "test_data"
BASE_URL = "https://www.example.com"


def load_json_file(file_name: str) -> list[dict[str, Any]] | dict[str, Any]:
    """Load the content of a JSON file.

    Args:
        file_name (str): Name of the JSON file to read and load.
    Returns:
        list[dict[str, Any]] | dict[str, Any]: Loaded file's content.
    """
    file_path = os.path.join(TEST_DATA, file_name)

    with open(file_path) as mock_file:
        return json.loads(mock_file.read())


@pytest.fixture()
def mock_client() -> SymantecEmailSecurity.Client:
    """Establish a mock connection to the API client.

    Returns:
        Client: Mock connection to client.
    """
    return SymantecEmailSecurity.Client(
        base_url=BASE_URL,
        username="test",
        password="test",
    )


@pytest.fixture()
def mock_quarantine_client() -> SymantecEmailSecurity.QuarantineClient:
    """Establish a mock connection to the API client.

    Returns:
        Client: Mock connection to client.
    """
    return SymantecEmailSecurity.QuarantineClient(
        base_url=BASE_URL,
        username="test",
        password="test",
    )


class MockClient:
    def __init__(self):
        self.calls = 0

    @SymantecEmailSecurity.pagination(items_key="items")
    def mock_api_call(self, start_index: int = 0, page_size: int = 2):
        """Mock API call that returns paginated results.

        Args:
            start_index (int, optional): The index to start fetching items from.
                Defaults to 0.
            page_size (int, optional): The number of items to return per page.
                Defaults to 2.

        Returns:
            dict[str, Any]: A dictionary containing the paginated items.
        """
        start_index = start_index or 0
        self.calls += 1
        data = [{"id": i} for i in range(start_index, start_index + page_size)]

        return {"items": data}


def test_pagination_manual() -> None:
    """
    Scenario:
    - Test manual pagination by calling the mock API for a specific page.

    Given:
    - A mock API function that simulates paginated results.

    When:
    - The mock API is called with `page=2` and `page_size=2`.

    Then:
    - Ensure that the correct items for the second page are returned.
    - Ensure that only one API call is made.
    """
    client = MockClient()
    response = client.mock_api_call(page=2, page_size=2)

    assert response["items"] == [{"id": 2}, {"id": 3}]
    assert client.calls == 1


def test_pagination_automatic() -> None:
    """
    Scenario:
    - Test automatic pagination by calling the mock API to retrieve multiple items.

    Given:
    - A mock API function that simulates paginated results.

    When:
    - The mock API is called with a `limit=4`.

    Then:
    - Ensure that the correct number of items (4) are returned.
    - Ensure that two API calls are made to fetch all items (as page size is 2).
    """
    SymantecEmailSecurity.DEFAULT_LIMIT = 3
    SymantecEmailSecurity.QUARANTINE_API_MAX_LIMIT = 2

    client = MockClient()
    response = client.mock_api_call(limit=4)

    assert response["items"] == [{"id": 0}, {"id": 1}, {"id": 2}, {"id": 3}]
    assert client.calls == 2


@SymantecEmailSecurity.validate_response
def mock_successful_api_call() -> dict[str, str]:
    """Mock API call that returns a successful response.

    Returns:
        dict[str, str]: A dictionary with a status of SUCCESS.
    """
    return {"status": "SUCCESS", "data": "Valid response"}


@SymantecEmailSecurity.validate_response
def mock_failed_api_call() -> dict[str, str]:
    """Mock API call that returns a failed response.

    Returns:
        dict[str, str]: A dictionary with a status of FAILURE.
    """
    return {"status": "FAILURE", "error": "Something went wrong"}


def test_validate_response_success() -> None:
    """
    Scenario:
    - Test the `validate_response` decorator for a successful response.

    Given:
    - A mock API function that returns a response with `status="SUCCESS"`.

    When:
    - The decorated function is called.

    Then:
    - Ensure that the function returns the original response as expected.
    """
    assert mock_successful_api_call() == {"status": "SUCCESS", "data": "Valid response"}


def test_validate_response_failure() -> None:
    """
    Scenario:
    - Test the `validate_response` decorator for a failed response.

    Given:
    - A mock API function that returns a response with `status="FAILURE"`.

    When:
    - The decorated function is called.

    Then:
    - Ensure that the function raises a `DemistoException` with the appropriate error message.
    """
    with pytest.raises(CommonServerPython.DemistoException):
        mock_failed_api_call()


@pytest.mark.parametrize(
    (
        "username,"
        "password,"
        "has_any_client_url,"
        "quarantine_username,"
        "quarantine_password,"
        "expect_client,"
        "expect_quarantine_client"
    ),
    [
        ("user", "pass", True, "user", "pass", True, True),  # Test creating both the clients
        ("user", "pass", True, None, None, True, False),  # Test creating only the regular client
        (None, None, False, "q_user", "q_pass", False, True),  # Test creating only the quarantine client
    ],
)
def test_determine_clients(
    username: str | None,
    password: str | None,
    has_any_client_url: bool,
    quarantine_username: str | None,
    quarantine_password: str | None,
    expect_client: bool,
    expect_quarantine_client: bool,
) -> None:
    """
    Scenario:
    - Test creating either the regular client or the quarantine client based on the input.

    Given:
    - Valid credentials and URL for either the regular client or the quarantine client.

    When:
    - `determine_clients` is called.

    Then:
    - Ensure that the appropriate client(s) are created or not, depending on the input.
    """
    command = "some-command"
    client, quarantine_client = SymantecEmailSecurity.determine_clients(
        command=command,
        username=username,
        password=password,
        command_to_url={command: "https://example.com"},
        has_any_client_url=has_any_client_url,
        quarantine_username=quarantine_username,
        quarantine_password=quarantine_password,
        url_quarantine="https://example.com/quarantine",
        verify_certificate=False,
        proxy=False,
    )

    if expect_client:
        assert client is not None
    else:
        assert client is None

    if expect_quarantine_client:
        assert quarantine_client is not None
    else:
        assert quarantine_client is None


@pytest.mark.parametrize(
    ("username,password,url_regular,quarantine_username,quarantine_password,url_quarantine,expected_message"),
    [
        # Test for mismatched credentials (only username is provided)
        (
            "user",
            None,
            "https://example.com",
            None,
            None,
            "https://example.com/quarantine",
            "Both username and password must be present when adding credentials.",
        ),
        # Test for missing URL for the regular client
        (
            "user",
            "pass",
            None,
            None,
            None,
            "https://example.com/quarantine",
            "Missing URL for 'Credentials', please fill the correct URL according to the mapping in 'Help'.",
        ),
        # Test for missing quarantine URL
        (
            None,
            None,
            "https://example.com",
            "q_user",
            "q_pass",
            None,
            "Missing URL for 'Quarantine Credentials', please fill 'Server URL - Quarantine'.",
        ),
        # Test for no credentials provided.
        (
            None,
            None,
            None,
            None,
            None,
            None,
            "At least one of the credentials must be filled.",
        ),
    ],
)
def test_determine_clients_exceptions(
    username: str | None,
    password: str | None,
    url_regular: str | None,
    quarantine_username: str | None,
    quarantine_password: str | None,
    url_quarantine: str | None,
    expected_message: str,
) -> None:
    """
    Scenario:
    - Mismatched credentials, missing URL for the client, or missing URL for the quarantine client.

    Given:
    - Various invalid combinations of credentials and URLs.

    When:
    - `determine_clients` is called.

    Then:
    - Ensure that the appropriate `DemistoException` is raised with the correct message.
    """
    command = "some-command"
    command_to_url = {command: url_regular}

    with pytest.raises(CommonServerPython.DemistoException, match=expected_message):
        SymantecEmailSecurity.determine_clients(
            command=command,
            username=username,
            password=password,
            has_any_client_url=False,
            command_to_url=command_to_url,
            quarantine_username=quarantine_username,
            quarantine_password=quarantine_password,
            url_quarantine=url_quarantine,
            verify_certificate=False,
            proxy=False,
        )


@pytest.mark.parametrize(
    "input, expected",
    [
        ("2023-10-15T12:34:56.789123Z", "2023-10-15T12:34:56Z"),
        ("2023-10-15T12:34:56", "2023-10-15T12:34:56Z"),
        ("0", datetime(1970, 1, 1, 0, 0, 0).isoformat() + "Z"),
    ],
)
def test_convert_datetime_string(input: str, expected: str) -> None:
    """
    Scenario:
    - Test converting datetime strings to ISO 8601 format with microseconds set to zero.

    Given:
    - Various datetime strings with different formats and microseconds.

    When:
    - convert_datetime_string is called with these datetime strings.

    Then:
    - Ensure that the returned string is in the correct ISO 8601 format without microseconds and with 'Z' appended.
    - Ensure that microseconds are set to zero in the output.
    """
    assert SymantecEmailSecurity.convert_datetime_string(input) == expected


@pytest.mark.parametrize(
    "input, expected",
    [
        ("1970-01-01T00:00:00Z", "0"),
        ("2023-10-15T12:34:56", str(int(datetime(2023, 10, 15, 12, 34, 56).timestamp() * 1000))),
        ("0", "0"),  # This assumes "0" is treated as epoch time, Jan 1, 1970
        (None, None),
    ],
)
def test_convert_to_epoch_timestamp(input: str | None, expected: str | None) -> None:
    """
    Scenario:
    - Test converting datetime strings to epoch timestamps in milliseconds.

    Given:
    - Various datetime strings or None values.

    When:
    - convert_to_epoch_timestamp is called with these datetime strings.

    Then:
    - Ensure that the returned value is the correct epoch timestamp in milliseconds or None.
    """
    assert SymantecEmailSecurity.convert_to_epoch_timestamp(input) == expected


@pytest.mark.parametrize(
    "input, expected",
    [
        (None, None),
        (True, True),
        (False, False),
        ("true", True),
        ("false", False),
    ],
)
def test_arg_to_optional_bool(input: Any, expected: None | bool) -> None:
    """
    Scenario:
    - Test converting various inputs to optional boolean values.

    Given:
    - Various inputs of different types.

    When:
    - arg_to_optional_bool is called with these inputs.

    Then:
    - Ensure that the returned value is either None or the correct boolean representation.
    """
    assert SymantecEmailSecurity.arg_to_optional_bool(input) == expected


def test_list_ioc_command(requests_mock, mock_client: SymantecEmailSecurity.Client) -> None:
    """
    Scenario:
    - Test retrieving a list of items through an HTTP request.

    Given:
    - limit.

    When:
    - ioc_list_command is called

    Then:
    - Ensure that the CommandResults outputs_prefix is correct.
    - Ensure that the CommandResults outputs_key_field is correct.
    - Ensure that the CommandResults outputs is correct.
    - Ensure that the CommandResults readable_output is correct.
    - Ensure that the CommandResults raw_response is correct.
    """
    mock_response = load_json_file("ioc_list_response.json")
    mock_table = load_json_file("ioc_list_table.json")

    endpoint = CommonServerPython.urljoin(BASE_URL, "domains/global/iocs/download")

    requests_mock.get(url=endpoint, json=mock_response)

    command_results = SymantecEmailSecurity.list_ioc_command(mock_client, {"limit": 5})

    assert command_results.outputs_prefix == f"{SymantecEmailSecurity.INTEGRATION_PREFIX}.IOC"
    assert command_results.outputs_key_field == "iocBlackListId"
    assert command_results.outputs == mock_response
    assert command_results.readable_output == CommonServerPython.tableToMarkdown(
        name="IOC(s)",
        t=mock_table,
        headers=[
            "ID",
            "Type",
            "Value",
            "Status",
            "Description",
            "Email Direction",
            "Remediation Action",
            "Expiry Date",
        ],
    )
    assert command_results.raw_response == mock_response


@pytest.mark.parametrize(
    "args, iocs",
    [
        (
            {"action": "ioc", "entry_id": "000"},
            [
                {
                    "APIRowAction": "A",
                    "IocType": "subject",
                    "IocValue": "Test",
                    "Description": "Test",
                    "EmailDirection": "I",
                },
                {
                    "APIRowAction": "R",
                    "IocBlacklistId": "00000000-0000-0000-0000-000000000000",
                    "IocType": "subject",
                    "IocValue": "Test",
                    "Description": "Test",
                    "EmailDirection": "O",
                    "RemediationAction": "H",
                },
                {
                    "APIRowAction": "U",
                    "IocBlacklistId": "00000000-0000-0000-0000-000000000000",
                    "IocType": "subject",
                    "IocValue": "Test",
                    "Description": "Test",
                    "EmailDirection": "O",
                    "RemediationAction": "H",
                },
                {
                    "APIRowAction": "D",
                    "IocBlacklistId": "00000000-0000-0000-0000-000000000000",
                    "IocType": "subject",
                    "IocValue": "Test",
                    "Description": "Test",
                    "EmailDirection": "O",
                    "RemediationAction": "H",
                },
            ],
        ),
        (
            {"action": "merge", "entry_id": "000"},
            [
                {
                    "IocType": "url",
                    "IocValue": "Test",
                    "Description": "Test",
                    "EmailDirection": "I",
                }
            ],
        ),
        (
            {"action": "replace", "entry_id": "000"},
            [
                {
                    "IocType": "url",
                    "IocValue": "Test",
                    "Description": "Test",
                    "EmailDirection": "I",
                }
            ],
        ),
    ],
)
def test_action_ioc_command_success_multiple_ioc(
    requests_mock,
    mock_client: SymantecEmailSecurity.Client,
    args: dict[str, Any],
    iocs: list[dict[str, Any]],
) -> None:
    """
    Scenario:
    - Test build IOCs through all scenarios.

    Given:
    - An `entry_id` with an `action`.

    When:
    - ioc_action_command

    Then:
    - Ensure that the CommandResults readable_output is correct.
    """
    read_data = json.dumps(iocs)
    mocked_open = unittest.mock.mock_open(read_data=read_data)

    endpoint = CommonServerPython.urljoin(BASE_URL, "domains/global/iocs/upload")

    requests_mock.post(url=endpoint, json=[])

    with unittest.mock.patch("builtins.open", mocked_open):
        command_results = SymantecEmailSecurity.action_ioc_command(mock_client, args)

    assert command_results.readable_output == "## All IOC(s) were uploaded successfully."


@pytest.mark.parametrize(
    "args",
    [
        {
            "action": "merge",
            "ioc_type": "subject",
            "ioc_value": "Test",
            "description": "Test",
            "email_direction": "inbound",
            "remediation_action": "quarantine",
        },
        {
            "action": "replace",
            "ioc_type": "subject",
            "ioc_value": "Test",
            "description": "Test",
            "email_direction": "inbound",
            "remediation_action": "quarantine",
        },
        {
            "action": "add",
            "ioc_type": "subject",
            "ioc_value": "Test",
            "description": "Test",
            "email_direction": "inbound",
            "remediation_action": "quarantine",
        },
        {
            "action": "update",
            "ioc_id": "00000000-0000-0000-0000-000000000000",
            "ioc_type": "subject",
            "ioc_value": "Test",
            "description": "Test",
            "email_direction": "inbound",
            "remediation_action": "quarantine",
        },
        {
            "action": "delete",
            "ioc_id": "00000000-0000-0000-0000-000000000000",
            "ioc_type": "subject",
            "ioc_value": "Test",
            "description": "Test",
            "email_direction": "inbound",
            "remediation_action": "quarantine",
        },
        {
            "action": "renew",
            "ioc_id": "00000000-0000-0000-0000-000000000000",
            "ioc_type": "subject",
            "ioc_value": "Test",
            "description": "Test",
            "email_direction": "inbound",
            "remediation_action": "quarantine",
        },
    ],
)
def test_action_ioc_command_success_single_ioc(
    requests_mock,
    mock_client: SymantecEmailSecurity.Client,
    args: dict[str, Any],
) -> None:
    """
    Scenario:
    - Test build IOCs through all scenarios.

    Given:
    - All arguments except for `entry_id`.

    When:
    - ioc_action_command

    Then:
    - Ensure that the CommandResults readable_output is correct.
    """
    endpoint = CommonServerPython.urljoin(BASE_URL, "domains/global/iocs/upload")
    requests_mock.post(url=endpoint, json=[])

    command_results = SymantecEmailSecurity.action_ioc_command(mock_client, args)

    assert command_results.readable_output == "## All IOC(s) were uploaded successfully."


@pytest.mark.parametrize(
    "args, iocs, error_message",
    [
        (
            {"action": "ioc", "entry_id": "000"},
            [
                {
                    "APIRowAction": "A",
                    "IocBlacklistId": "00000000-0000-0000-0000-000000000000",
                    "IocType": "subject",
                    "IocValue": "Test",
                    "Description": "Test",
                    "EmailDirection": "I",
                },
            ],
            "IocBlacklistId should not be present for APIRowAction=A (Add).",
        ),
        (
            {"action": "ioc", "entry_id": "000"},
            [
                {
                    "APIRowAction": "R",
                    "IocType": "subject",
                    "IocValue": "Test",
                    "Description": "Test",
                    "EmailDirection": "O",
                    "RemediationAction": "H",
                },
            ],
            "IocBlacklistId must be present for APIRowAction=R.",
        ),
        (
            {"action": "ioc", "entry_id": "000"},
            [
                {
                    "IocBlacklistId": "00000000-0000-0000-0000-000000000000",
                    "IocType": "subject",
                    "IocValue": "Test",
                    "Description": "Test",
                    "EmailDirection": "O",
                    "RemediationAction": "H",
                },
            ],
            "APIRowAction must be present for action=ioc.",
        ),
        (
            {"action": "ioc", "entry_id": "000"},
            [
                {
                    "APIRowAction": "D",
                    "IocType": "subject",
                    "IocValue": "Test",
                    "Description": "Test",
                    "EmailDirection": "O",
                    "RemediationAction": "H",
                },
            ],
            "IocBlacklistId must be present for APIRowAction=D.",
        ),
        (
            {"action": "merge", "entry_id": "000"},
            [
                {
                    "IocBlacklistId": "00000000-0000-0000-0000-000000000000",
                    "IocType": "url",
                    "IocValue": "Test",
                    "Description": "Test",
                    "EmailDirection": "I",
                }
            ],
            "APIRowAction and IocBlacklistId should be omitted or blank for MERGE requests.",
        ),
        (
            {"action": "replace", "entry_id": "000"},
            [
                {
                    "APIRowAction": "A",
                    "IocType": "url",
                    "IocValue": "Test",
                    "Description": "Test",
                    "EmailDirection": "I",
                }
            ],
            "APIRowAction and IocBlacklistId should be omitted or blank for REPLACE requests.",
        ),
        (
            {"action": "add", "entry_id": "000"},
            [],
            "The field `entry_id` is only compatible with `action=merge/replace/ioc`.",
        ),
        (
            {"action": "delete", "entry_id": "000"},
            [],
            "The field `entry_id` is only compatible with `action=merge/replace/ioc`.",
        ),
        (
            {"action": "renew", "entry_id": "000"},
            [],
            "The field `entry_id` is only compatible with `action=merge/replace/ioc`.",
        ),
        (
            {"action": "update", "entry_id": "000"},
            [],
            "The field `entry_id` is only compatible with `action=merge/replace/ioc`.",
        ),
    ],
)
def test_action_ioc_command_error_multiple_ioc(
    requests_mock,
    mock_client: SymantecEmailSecurity.Client,
    args: dict[str, Any],
    iocs: list[dict[str, Any]],
    error_message: str,
) -> None:
    """
    Scenario:
    - Test exception handling when build IOCs from a dict.

    Given:
    - An `entry_id` with an `action`.

    When:
    - ioc_action_command

    Then:
    - Ensure that the error message is raised.
    """
    read_data = json.dumps(iocs)
    mocked_open = unittest.mock.mock_open(read_data=read_data)

    endpoint = CommonServerPython.urljoin(BASE_URL, "domains/global/iocs/upload")

    requests_mock.post(url=endpoint, json=[])

    with unittest.mock.patch("builtins.open", mocked_open), pytest.raises(CommonServerPython.DemistoException) as e:
        SymantecEmailSecurity.action_ioc_command(mock_client, args)

    assert str(e.value) == error_message


@pytest.mark.parametrize(
    "args, error_message",
    [
        (
            {"action": "ioc"},
            "`action=ioc` is only compatible with `entry_id`.",
        ),
        (
            {
                "action": "merge",
                "ioc_id": "00000000-0000-0000-0000-000000000000",
                "ioc_type": "subject",
                "ioc_value": "Test",
                "description": "Test",
                "email_direction": "inbound",
                "remediation_action": "quarantine",
            },
            "APIRowAction and IocBlacklistId should be omitted or blank for MERGE requests.",
        ),
        (
            {
                "action": "merge",
                "email_direction": "inbound",
                "remediation_action": "quarantine",
            },
            "Fields IocType, IocValue, Description, and EmailDirection are mandatory.",
        ),
        (
            {
                "action": "replace",
                "ioc_id": "00000000-0000-0000-0000-000000000000",
                "ioc_type": "subject",
                "ioc_value": "Test",
                "description": "Test",
                "email_direction": "inbound",
                "remediation_action": "quarantine",
            },
            "APIRowAction and IocBlacklistId should be omitted or blank for REPLACE requests.",
        ),
        (
            {
                "action": "add",
                "ioc_id": "00000000-0000-0000-0000-000000000000",
                "ioc_type": "subject",
                "ioc_value": "Test",
                "description": "Test",
                "email_direction": "inbound",
                "remediation_action": "quarantine",
            },
            "IocBlacklistId should not be present for APIRowAction=A (Add).",
        ),
        (
            {
                "action": "update",
                "ioc_type": "subject",
                "ioc_value": "Test",
                "description": "Test",
                "email_direction": "inbound",
                "remediation_action": "quarantine",
            },
            "IocBlacklistId must be present for APIRowAction=U.",
        ),
        (
            {
                "action": "delete",
                "ioc_type": "subject",
                "ioc_value": "Test",
                "description": "Test",
                "email_direction": "inbound",
                "remediation_action": "quarantine",
            },
            "IocBlacklistId must be present for APIRowAction=D.",
        ),
        (
            {
                "action": "renew",
                "ioc_type": "subject",
                "ioc_value": "Test",
                "description": "Test",
                "email_direction": "inbound",
                "remediation_action": "quarantine",
            },
            "IocBlacklistId must be present for APIRowAction=R.",
        ),
    ],
)
def test_action_ioc_command_error_single_ioc(
    requests_mock,
    mock_client: SymantecEmailSecurity.Client,
    args: dict[str, Any],
    error_message: str,
) -> None:
    """
    Scenario:
    - Test build IOCs through all scenarios.

    Given:
    - All arguments except for `entry_id`.

    When:
    - ioc_action_command

    Then:
    - Ensure that the CommandResults readable_output is correct.
    """
    endpoint = CommonServerPython.urljoin(BASE_URL, "domains/global/iocs/upload")
    requests_mock.post(url=endpoint, json=[])

    with pytest.raises(CommonServerPython.DemistoException) as e:
        SymantecEmailSecurity.action_ioc_command(mock_client, args)

    assert str(e.value) == error_message


def test_action_ioc_command_failure_multiple_ioc(requests_mock, mock_client: SymantecEmailSecurity.Client) -> None:
    """
    Scenario:
    - Test build IOCs through all scenarios.

    Given:
    - An `entry_id` with an `action`.

    When:
    - ioc_action_command

    Then:
    - Ensure that the CommandResults readable_output is correct.
    """
    iocs = [
        {
            "APIRowAction": "A",
            "IocType": "subject",
            "IocValue": "Test",
            "Description": "Test",
            "EmailDirection": "I",
        }
    ]
    read_data = json.dumps(iocs)
    mocked_open = unittest.mock.mock_open(read_data=read_data)

    endpoint = CommonServerPython.urljoin(BASE_URL, "domains/global/iocs/upload")
    response = [
        {
            "iocBlackListId": "000",
            "iocType": "subject",
            "iocValue": "Test",
            "failureReason": "Hello World!",
        },
        {
            "iocType": "subject",
            "iocValue": "Test",
            "failureReason": "Hello World!",
        },
    ]

    requests_mock.post(url=endpoint, json=response)

    args = {"action": "ioc", "entry_id": "000"}

    with unittest.mock.patch("builtins.open", mocked_open):
        command_results = SymantecEmailSecurity.action_ioc_command(mock_client, args)

    assert command_results.readable_output == "## The following IOC(s) failed:\n- 000: Hello World!\n- subject-Test: Hello World!"


def test_renew_ioc_command_success(requests_mock, mock_client: SymantecEmailSecurity.Client) -> None:
    """
    Scenario:
    - Test renewing all IOCs in the API.

    Given:
    - Nothing.

    When:
    - ioc_renew_command is called

    Then:
    - Ensure that the CommandResults readable_output is correct.
    """
    endpoint = CommonServerPython.urljoin(BASE_URL, "domains/global/iocs/renewall")
    requests_mock.post(url=endpoint, json={}, headers={"x-status": "SUCCESS"})

    command_results = SymantecEmailSecurity.renew_ioc_command(mock_client, {})
    assert command_results.readable_output == "## All IOC(s) were renewed."


def test_renew_ioc_command_error(requests_mock, mock_client: SymantecEmailSecurity.Client) -> None:
    """
    Scenario:
    - Test renewing all IOCs in the API.

    Given:
    - Nothing.

    When:
    - ioc_renew_command is called

    Then:
    - Ensure that an error is raised with the correct message.
    """
    endpoint = CommonServerPython.urljoin(BASE_URL, "domains/global/iocs/renewall")
    requests_mock.post(url=endpoint, json={}, headers={"x-status": "FAILURE"})

    with pytest.raises(CommonServerPython.DemistoException) as e:
        SymantecEmailSecurity.renew_ioc_command(mock_client, {})

    assert str(e.value) == "Failed to renew IOCs, reason: None."


def test_list_email_queue_command(requests_mock, mock_client: SymantecEmailSecurity.Client) -> None:
    """
    Scenario:
    - Test retrieving a list of items through an HTTP request.

    Given:
    - limit.

    When:
    - email_queue_list is called

    Then:
    - Ensure that the CommandResults outputs_prefix is correct.
    - Ensure that the CommandResults outputs is correct.
    - Ensure that the CommandResults readable_output is correct.
    - Ensure that the CommandResults raw_response is correct.
    """
    mock_response = load_json_file("email_queue_list_response.json")

    endpoint = CommonServerPython.urljoin(BASE_URL, "stats")

    requests_mock.get(url=endpoint, json=mock_response)

    command_results = SymantecEmailSecurity.list_email_queue_command(mock_client, {"limit": 5})

    expected_readable_output = (
        CommonServerPython.tableToMarkdown(
            name="Email Queue Statistic(s)",
            t=mock_response,
            headerTransform=CommonServerPython.string_to_table_header,
            headers=[
                "TotalMessagesInbound",
                "TotalMessagesOutbound",
                "MeanTimeInQueueInbound",
                "MeanTimeInQueueOutbound",
                "LongestTimeInInbound",
                "LongestTimeInOutbound",
            ],
        )
        + "\n"
        + CommonServerPython.tableToMarkdown(
            name="Domain Statistic(s)",
            t=mock_response["Domains"],
            headerTransform=CommonServerPython.string_to_table_header,
            headers=[
                "Name",
                "ReceiveQueueCountInbound",
                "ReceiveQueueCountOutbound",
                "DeliveryQueueCountInbound",
                "DeliveryQueueCountOutbound",
            ],
        )
    )

    assert command_results.outputs_prefix == f"{SymantecEmailSecurity.INTEGRATION_PREFIX}.EmailQueue"
    assert command_results.outputs == mock_response
    assert command_results.readable_output == expected_readable_output
    assert command_results.raw_response == mock_response


def test_list_data_command(requests_mock, mock_client: SymantecEmailSecurity.Client) -> None:
    """
    Scenario:
    - Test retrieving a list of items through an HTTP request.

    Given:
    - limit.

    When:
    - data_list_command is called

    Then:
    - Ensure that the CommandResults outputs_prefix is correct.
    - Ensure that the CommandResults outputs is correct.
    - Ensure that the CommandResults readable_output is correct.
    - Ensure that the CommandResults raw_response is correct.
    """
    mock_response = load_json_file("data_list_response.json")
    mock_table = load_json_file("data_list_table.json")

    endpoint = CommonServerPython.urljoin(BASE_URL, "all")

    requests_mock.get(url=endpoint, json="Reset successfully")
    requests_mock.get(url=endpoint, json=mock_response)

    command_results = SymantecEmailSecurity.list_data_command(mock_client, {"limit": 5, "fetch_only_incidents": "true"})

    assert command_results.outputs_prefix == f"{SymantecEmailSecurity.INTEGRATION_PREFIX}.Data"
    assert command_results.outputs == mock_response
    assert command_results.readable_output == CommonServerPython.tableToMarkdown(
        name="Email Data Feed(s)",
        t=mock_table,
        headers=[
            "Message Size",
            "Subject",
            "Envelope From",
            "Envelope To",
            "Sender IP",
            "Sender Mail Server",
            "File/URLs With Risk",
            "Incidents",
        ],
    )
    assert command_results.raw_response == mock_response


@pytest.mark.parametrize(
    (
        "list_command,"
        "args,"
        "endpoint_suffix,"
        "response_file,"
        "table_file,"
        "readable_output_title,"
        "outputs_prefix,"
        "outputs_key,"
    ),
    [
        (
            SymantecEmailSecurity.list_quarantine_email_command,
            {},
            "v1/mails",
            "quarantine_email_list_response.json",
            "quarantine_email_list_table.json",
            "Quarantine Email(s)",
            f"{SymantecEmailSecurity.INTEGRATION_PREFIX}.QuarantineEmail",
            "mail_list",
        ),
        (
            SymantecEmailSecurity.list_item_allow_block_command,
            {"access_control": SymantecEmailSecurity.AccessControl.WHITELIST.value},
            "v1/users/whitelist",
            "item_allow_block_list_response.json",
            "item_allow_block_list_table.json",
            "Allow List Item(s)",
            f"{SymantecEmailSecurity.INTEGRATION_PREFIX}.Allow",
            "items",
        ),
        (
            SymantecEmailSecurity.list_item_allow_block_command,
            {"access_control": SymantecEmailSecurity.AccessControl.BLACKLIST.value},
            "v1/users/blacklist",
            "item_allow_block_list_response.json",
            "item_allow_block_list_table.json",
            "Block List Item(s)",
            f"{SymantecEmailSecurity.INTEGRATION_PREFIX}.Block",
            "items",
        ),
    ],
)
def test_automatic_pagination_commands(
    requests_mock,
    mock_quarantine_client: SymantecEmailSecurity.QuarantineClient,
    list_command: Callable[[SymantecEmailSecurity.Client, dict[str, Any]], CommonServerPython.CommandResults],
    args: dict[str, Any],
    endpoint_suffix: str,
    response_file: str,
    table_file: str,
    readable_output_title: str,
    outputs_prefix: str,
    outputs_key: str,
) -> None:
    """
    Scenario:
    - Test retrieving a list of objects through making multiple HTTP requests.

    Given:
    - Command args and a `limit`.

    When:
    - quarantine_email_list_command
    - item_allow_block_list_command

    Then:
    - Ensure that the CommandResults outputs_prefix is correct.
    - Ensure that the CommandResults outputs_key_field is correct.
    - Ensure that the CommandResults outputs is correct.
    - Ensure that the CommandResults readable_output is correct.
    - Ensure that the CommandResults raw_response is correct.
    """
    args["sort_order"] = "desc"
    args["limit"] = 5
    SymantecEmailSecurity.QUARANTINE_API_MAX_LIMIT = 2

    mock_response = load_json_file(response_file)
    mock_table = load_json_file(table_file)

    endpoint = CommonServerPython.urljoin(BASE_URL, endpoint_suffix)
    number_of_calls = args["limit"] // SymantecEmailSecurity.QUARANTINE_API_MAX_LIMIT

    for i in range(number_of_calls + 1):
        expected_output = mock_response[outputs_key][number_of_calls * i : number_of_calls * (i + 1)]

        if not expected_output:
            break

        current_mock_response = copy.copy(mock_response)
        current_mock_response[outputs_key] = expected_output

        start_index = i * SymantecEmailSecurity.QUARANTINE_API_MAX_LIMIT

        if i == 0:
            page_size = SymantecEmailSecurity.QUARANTINE_API_MAX_LIMIT
        else:
            page_size = len(expected_output)

        requests_mock.get(
            url=f"{endpoint}?sort_order=desc&{f'{start_index=}&' if i else ''}{page_size=}",
            json=current_mock_response,
        )

    command_results = list_command(mock_quarantine_client, args)

    assert command_results.outputs_prefix == outputs_prefix
    assert command_results.outputs_key_field == "id"
    assert command_results.outputs == mock_response[outputs_key]
    assert command_results.readable_output == CommonServerPython.tableToMarkdown(
        name=readable_output_title,
        t=mock_table,
        headers=list(mock_table[0]),
    )
    assert command_results.raw_response == mock_response


@pytest.mark.parametrize(
    (
        "list_command,"
        "args,"
        "endpoint_suffix,"
        "response_file,"
        "table_file,"
        "readable_output_title,"
        "outputs_prefix,"
        "outputs_key,"
    ),
    [
        (
            SymantecEmailSecurity.list_quarantine_email_command,
            {},
            "v1/mails",
            "quarantine_email_list_response.json",
            "quarantine_email_list_table.json",
            "Quarantine Email(s)",
            f"{SymantecEmailSecurity.INTEGRATION_PREFIX}.QuarantineEmail",
            "mail_list",
        ),
        (
            SymantecEmailSecurity.list_item_allow_block_command,
            {"access_control": SymantecEmailSecurity.AccessControl.WHITELIST.value},
            "v1/users/whitelist",
            "item_allow_block_list_response.json",
            "item_allow_block_list_table.json",
            "Allow List Item(s)",
            f"{SymantecEmailSecurity.INTEGRATION_PREFIX}.Allow",
            "items",
        ),
        (
            SymantecEmailSecurity.list_item_allow_block_command,
            {"access_control": SymantecEmailSecurity.AccessControl.BLACKLIST.value},
            "v1/users/blacklist",
            "item_allow_block_list_response.json",
            "item_allow_block_list_table.json",
            "Block List Item(s)",
            f"{SymantecEmailSecurity.INTEGRATION_PREFIX}.Block",
            "items",
        ),
    ],
)
def test_manual_pagination_commands(
    requests_mock,
    mock_quarantine_client: SymantecEmailSecurity.QuarantineClient,
    list_command: Callable[[SymantecEmailSecurity.Client, dict[str, Any]], CommonServerPython.CommandResults],
    args: dict[str, Any],
    endpoint_suffix: str,
    response_file: str,
    table_file: str,
    readable_output_title: str,
    outputs_prefix: str,
    outputs_key: str,
) -> None:
    """
    Scenario:
    - Test retrieving a list of objects through making a paginated HTTP requests.

    Given:
    - Command args, `page` and `page_size`.

    When:
    - quarantine_email_list_command
    - item_allow_block_list_command

    Then:
    - Ensure that the CommandResults outputs_prefix is correct.
    - Ensure that the CommandResults outputs_key_field is correct.
    - Ensure that the CommandResults outputs is correct.
    - Ensure that the CommandResults readable_output is correct.
    - Ensure that the CommandResults raw_response is correct.
    """
    args["page"] = 1
    args["page_size"] = 5

    mock_response = load_json_file(response_file)
    mock_table = load_json_file(table_file)

    requests_mock.get(
        url=CommonServerPython.urljoin(BASE_URL, endpoint_suffix),
        json=mock_response,
    )

    command_results = list_command(mock_quarantine_client, args)

    assert command_results.outputs_prefix == outputs_prefix
    assert command_results.outputs_key_field == "id"
    assert command_results.outputs == mock_response[outputs_key]
    assert command_results.readable_output == CommonServerPython.tableToMarkdown(
        name=readable_output_title,
        t=mock_table,
        headers=list(mock_table[0]),
    )
    assert command_results.raw_response == mock_response


def test_preview_quarantine_email_command(
    requests_mock,
    mock_quarantine_client: SymantecEmailSecurity.QuarantineClient,
):
    """
    Scenario:
    - Test previewing a quarantine email.

    Given:
    - Command args, `message_id`.

    When:
    - preview_quarantine_email_command

    Then:
    - Ensure that the CommandResults outputs_prefix is correct.
    - Ensure that the CommandResults outputs_key_field is correct.
    - Ensure that the CommandResults outputs is correct.
    - Ensure that the CommandResults readable_output is correct.
    - Ensure that the CommandResults raw_response is correct.
    """
    args = {"message_id": "000"}

    mock_response = load_json_file("quarantine_email_preview_response.json")
    mock_table = load_json_file("quarantine_email_preview_table.json")

    requests_mock.get(
        url=CommonServerPython.urljoin(BASE_URL, "v1/mails/preview"),
        json=mock_response,
    )

    command_results = SymantecEmailSecurity.preview_quarantine_email_command(mock_quarantine_client, args)

    mock_response["details"]["message_id"] = args["message_id"]
    expected_outputs = mock_response["details"]
    expected_readable_output = (
        CommonServerPython.tableToMarkdown(
            name="Quarantine Email Preview",
            t=mock_table["headers"],
            headers=list(mock_table["headers"]),
        )
        + CommonServerPython.tableToMarkdown(
            name="Attachments",
            t=mock_table["attachments"],
            headers=list(mock_table["attachments"][0]),
        )
        + CommonServerPython.tableToMarkdown(
            name="Body Parts",
            t=mock_table["bodypart"],
        )
    )

    assert command_results.outputs_prefix == f"{SymantecEmailSecurity.INTEGRATION_PREFIX}.QuarantineEmailPreview"
    assert command_results.outputs_key_field == "message_id"
    assert command_results.outputs == expected_outputs
    assert command_results.readable_output == expected_readable_output
    assert command_results.raw_response == mock_response


@pytest.mark.parametrize(
    "command,args,endpoint_suffix,readable_output_title",
    [
        (
            SymantecEmailSecurity.release_quarantine_email_command,
            {"message_ids": "000,111", "recipient": "hello", "headers": "hello,world"},
            "v1/mails/release",
            "## Successfully released all messages.",
        ),
        (
            SymantecEmailSecurity.delete_quarantine_email_command,
            {"message_ids": "000,111"},
            "v1/mails/delete",
            "## Successfully deleted all messages.",
        ),
        (
            SymantecEmailSecurity.update_item_allow_block_list_command,
            {
                "access_control": SymantecEmailSecurity.AccessControl.BLACKLIST.value,
                "suduls_user": "Lior",
                "email_or_domain": "was",
                "description": "here",
            },
            "v1/users/blacklist",
            "## The items were successfully merged.",
        ),
        (
            SymantecEmailSecurity.delete_item_allow_block_list_command,
            {"access_control": SymantecEmailSecurity.AccessControl.WHITELIST.value, "item_id": "000"},
            "v1/users/whitelist",
            "## The items were successfully deleted.",
        ),
    ],
)
def test_general_action_commands(
    requests_mock,
    mock_quarantine_client: SymantecEmailSecurity.QuarantineClient,
    command: Callable[[SymantecEmailSecurity.Client, dict[str, Any]], CommonServerPython.CommandResults],
    args: dict[str, Any],
    endpoint_suffix: str,
    readable_output_title: str,
) -> None:
    """
    Scenario:
    - Test several general commands

    Given:
    - Command args.

    When:
    - release_quarantine_email_command
    - delete_quarantine_email_command
    - update_item_allow_block_list_command
    - delete_item_allow_block_list_command

    Then:
    - Ensure that the CommandResults readable_output is correct.
    """
    requests_mock.post(
        url=CommonServerPython.urljoin(BASE_URL, endpoint_suffix),
        json={"status": "SUCCESS"},
    )

    command_results = command(mock_quarantine_client, args)
    assert command_results.readable_output == readable_output_title


def test_fetch_incidents(requests_mock, mock_client: SymantecEmailSecurity.Client) -> None:
    """
    Scenario:
    - Test fetch incidents.

    Given:
    - Arguments for initializing a fetch.

    When:
    - fetch_incidents is called.

    Then:
    - Ensure that the incidents are correct.
    - Ensure that the next_run is correct.
    """
    mock_response = load_json_file("data_list_response.json")

    endpoint = CommonServerPython.urljoin(BASE_URL, "all")

    requests_mock.get(url=endpoint, json="Reset successfully")
    requests_mock.get(url=endpoint, json=mock_response)

    next_run, incidents = SymantecEmailSecurity.fetch_incidents(
        client=mock_client,
        last_run={},
        first_fetch_time="3 days",
        max_results=2,
        accepted_severities=[CommonServerPython.IncidentSeverity.LOW],
        feed_type="all",
        include_delivery=True,
    )

    expected_incidents = [
        {
            "name": " - Email Data Feeds - Malware - 000",
            "occurred": "1970-01-12T13:46:40.000Z",
            "severity": 1,
            "details": "unknown",
            "rawJSON": json.dumps(mock_response[0] | {"incident_type": "email_data_feed"}),
        }
    ]
    expected_next_run = {
        "email_data_feeds": {
            "last_fetch": "1000000000",
            "last_ids": [
                "000",
            ],
        }
    }

    assert incidents == expected_incidents
    assert next_run == expected_next_run


def test_fetch_incidents_quarantine(
    requests_mock,
    mock_quarantine_client: SymantecEmailSecurity.QuarantineClient,
) -> None:
    """
    Scenario:
    - Test fetch quarantine incidents.

    Given:
    - Arguments for initializing a fetch.

    When:
    - fetch_incidents is called.

    Then:
    - Ensure that the incidents are correct.
    - Ensure that the next_run is correct.
    """
    mock_response = load_json_file("quarantine_email_list_response.json")
    mock_response_preview = load_json_file("quarantine_email_preview_response.json")

    mock_response["mail_list"] = mock_response["mail_list"][:1]

    requests_mock.get(url=CommonServerPython.urljoin(BASE_URL, "v1/mails"), json=mock_response)
    requests_mock.get(url=CommonServerPython.urljoin(BASE_URL, "v1/mails/preview"), json=mock_response_preview)

    next_run, incidents = SymantecEmailSecurity.fetch_incidents_quarantine(
        client=mock_quarantine_client,
        last_run={},
        first_fetch_time="3 days",
        max_results=2,
    )

    item = mock_response["mail_list"][0] | mock_response_preview["details"] | {"incident_type": "email_quarantine"}

    expected_incidents = [
        {
            "name": " - Email Quarantine - CI - 000",
            "occurred": "2024-10-06T09:20:41.000Z",
            "severity": CommonServerPython.IncidentSeverity.UNKNOWN,
            "details": "Reason: CC",
            "rawJSON": json.dumps(item),
        }
    ]
    expected_next_run = {
        "email_quarantine": {
            "last_fetch": "1728206441148",
            "last_ids": [
                "000",
            ],
        }
    }

    assert incidents == expected_incidents
    assert next_run == expected_next_run


def test_client_created_with_verify_and_proxy(mocker):
    """
    Given: params for test module
    When: configuring the integration
    Then: Validate the client created in the test module handle proxy.
    """
    from SymantecEmailSecurity import test_module

    mocker.patch.object(SymantecEmailSecurity.Client, "list_ioc", return_value=None)
    mock_client = mocker.patch.object(SymantecEmailSecurity, "Client")
    result = test_module(credentials=("username", "password"), url_ioc="https://iocapi.example.com", verify=True, proxy=True)

    # Assert
    assert result == "ok"
    mock_client.assert_called_with(
        "https://iocapi.example.com", username="username", password="password", verify=True, proxy=True
    )

    result = test_module(credentials=("username", "password"), url_ioc="https://iocapi.example.com", verify=True, proxy=False)

    mock_client.assert_called_with(
        "https://iocapi.example.com", username="username", password="password", verify=True, proxy=False
    )