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
| ID | Symantec Email Security Cloud |
|---|---|
| Provider | Broadcom |
| Category | |
| From Version | 5.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix 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
- IOC Management: Manage IOCs for email threats across domains: list, add, update, delete, or renew IOCs.
- Data Feeds: Retrieve threat data (e.g., malware, spam, clicks) for insights into email security events.
- Email Queue Monitoring: View queue statistics per domain to monitor email processing and delays.
- Quarantine Actions: List, preview, release, or delete quarantined emails to manage potentially harmful content.
- Allow and Block Lists: Maintain lists for permitted or restricted senders/domains: retrieve, add/update, or delete items.
- Fetch Incidents: Auto-fetch incidents and quarantine-specific threats to streamline response and compliance.
Configure Symantec Email Security Cloud on Cortex XSOAR
- Navigate to Settings > Integrations > Servers & Services.
- Search for Symantec Email Security Cloud.
-
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. - 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
#### Context Example
```json
{
"SymantecEmailSecurity": {
"IOC": {
"description": "url to block",
"emailDirection": "O",
"expiryDate": "2024-01-01 00:00:00.0",
"iocBlackListId": "00000000-0000-0000-0000-000000000000",
"iocType": "url",
"iocValue": "https://www.example.com",
"remediationAction": "H",
"status": "Active"
}
}
}
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
>## All IOC(s) were renewed
### 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).
#### Base Command
`symantec-email-security-data-list`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| feed_type | The type of the email data feed to retrieve. Possible values are: all, malware, threat-isolation, clicktime, anti-spam, ec-reports. Default is all. | Optional |
| start_from | Start time for reading metadata. Accepted formats: any substring of yyyy-mm-ddThh:mm:ssZ, epoch 1720617001, relative 1 day 2h 3 minute. Max start time is 1095 days before current date. Default is 3 days. | Optional |
| include_delivery | 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. Possible values are: false, true. | Optional |
| fetch_only_incidents | Whether to fetch only incident fields. Possible values are: true, false. | 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.Data.emailInfo.xMsgRef | String | Unique message reference identifier. |
| SymantecEmailSecurity.Data.emailInfo.longMsgRef | String | Detailed message reference path. |
| SymantecEmailSecurity.Data.emailInfo.messageId | String | Email's unique message identifier. |
| SymantecEmailSecurity.Data.emailInfo.isOutbound | Number | Indicates if the email is outbound. |
| SymantecEmailSecurity.Data.emailInfo.messageSize | Number | Size of the email message in bytes. |
| SymantecEmailSecurity.Data.emailInfo.mailProcessingStartTime | Number | Start time of email processing. |
| SymantecEmailSecurity.Data.emailInfo.subject | String | Subject line of the email. |
| SymantecEmailSecurity.Data.emailInfo.envFrom | String | Envelope sender of the email. |
| SymantecEmailSecurity.Data.emailInfo.envTo | String | Envelope receiver of the email. |
| SymantecEmailSecurity.Data.emailInfo.headerFrom | String | Header sender of the email. |
| SymantecEmailSecurity.Data.emailInfo.rawHeaderFrom | String | Raw header sender information. |
| SymantecEmailSecurity.Data.emailInfo.headerReplyTo | String | Reply-to address in email header. |
| SymantecEmailSecurity.Data.emailInfo.senderIp | String | IP address of the email sender. |
| SymantecEmailSecurity.Data.emailInfo.senderMailserver | String | Mail server of the email sender. |
| SymantecEmailSecurity.Data.emailInfo.country | String | Country of the email sender. |
| SymantecEmailSecurity.Data.emailInfo.HELOString | String | HELO string from the mail server. |
| SymantecEmailSecurity.Data.emailInfo.avQuarantinePenId | String | Quarantine pen ID for antivirus. |
| SymantecEmailSecurity.Data.emailInfo.authResults | Unknown | Authentication results of the email. |
| SymantecEmailSecurity.Data.emailInfo.filesAndLinks.nodeType | String | Type of node for files and links. |
| SymantecEmailSecurity.Data.emailInfo.filesAndLinks.fileNameOrURL | String | File name or URL in the email. |
| SymantecEmailSecurity.Data.emailInfo.filesAndLinks.fileSize | Number | Size of the file in the email. |
| SymantecEmailSecurity.Data.emailInfo.filesAndLinks.fileType | String | Type of the file in the email. |
| SymantecEmailSecurity.Data.emailInfo.filesAndLinks.md5 | String | MD5 hash of the file. |
| SymantecEmailSecurity.Data.emailInfo.filesAndLinks.sha256 | String | SHA-256 hash of the file. |
| SymantecEmailSecurity.Data.emailInfo.filesAndLinks.urlCategories | Unknown | Categories of URLs in the email. |
| SymantecEmailSecurity.Data.emailInfo.filesAndLinks.urlRiskScore | Unknown | Risk score of URLs in the email. |
| SymantecEmailSecurity.Data.emailInfo.filesAndLinks.index | Number | Index of the file/link in email. |
| SymantecEmailSecurity.Data.emailInfo.filesAndLinks.parentIndex | Number | Parent index of the file/link in email. |
| SymantecEmailSecurity.Data.emailInfo.filesAndLinks.linkSource | String | Source of the link in the email. |
| SymantecEmailSecurity.Data.emailInfo.tlsInfo.tlsAdvertised | Number | Indicates if TLS was advertised. |
| SymantecEmailSecurity.Data.emailInfo.tlsInfo.tlsUsed | Number | Indicates if TLS was used. |
| SymantecEmailSecurity.Data.emailInfo.tlsInfo.tlsPolicy | String | Policy for using TLS. |
| SymantecEmailSecurity.Data.emailInfo.tlsInfo.tlsProtocol | String | Protocol used for TLS. |
| SymantecEmailSecurity.Data.emailInfo.tlsInfo.tlsCipher | String | Cipher used for TLS. |
| SymantecEmailSecurity.Data.emailInfo.tlsInfo.tlsKeyLength | Number | Key length used for TLS. |
| SymantecEmailSecurity.Data.emailInfo.tlsInfo.tlsFallbackReason | String | Reason for TLS fallback. |
| SymantecEmailSecurity.Data.emailInfo.tlsInfo.tlsForwardSecrecy | Number | Indicates if forward secrecy was used. |
| SymantecEmailSecurity.Data.emailInfo.tlsInfo.tlsNegotiationFailed | Number | Indicates if TLS negotiation failed. |
| SymantecEmailSecurity.Data.emailInfo.newDomainAge | Unknown | Age of the new domain. |
| SymantecEmailSecurity.Data.emailInfo.timeInCynicSandboxMs | Number | Time spent in Cynic sandbox in ms. |
| SymantecEmailSecurity.Data.incidents | Unknown | Associated incidents. |
| SymantecEmailSecurity.Data.clicktimeInfo.xMsgRef | String | Unique click message reference. |
| SymantecEmailSecurity.Data.clicktimeInfo.squrlClickerIp | String | IP address of the URL clicker. |
| SymantecEmailSecurity.Data.clicktimeInfo.squrlRecipient | String | Recipient of the clicked URL. |
| SymantecEmailSecurity.Data.clicktimeInfo.url | String | Clicked URL. |
| SymantecEmailSecurity.Data.clicktimeInfo.dateUrlAccess | Number | Timestamp of URL access. |
| SymantecEmailSecurity.Data.clicktimeInfo.risk | Number | Risk level of the URL. |
| SymantecEmailSecurity.Data.incident | Unknown | Associated incident details. |
| SymantecEmailSecurity.Data.fireglass_log.timestamp | Date | Timestamp of the event. |
| SymantecEmailSecurity.Data.fireglass_log.event | String | Type of event logged. |
| SymantecEmailSecurity.Data.fireglass_log.source_ip | String | Source IP address of the event. |
| SymantecEmailSecurity.Data.fireglass_log.url | String | URL involved in the event. |
| SymantecEmailSecurity.Data.fireglass_log.referer_url | String | Referer URL of the event. |
| SymantecEmailSecurity.Data.fireglass_log.request_method | String | HTTP request method used. |
| SymantecEmailSecurity.Data.fireglass_log.user_agent | String | User agent string of the request. |
| SymantecEmailSecurity.Data.fireglass_log.destination_ip | String | Destination IP address of the event. |
| SymantecEmailSecurity.Data.fireglass_log.action | String | Action taken for the event. |
| SymantecEmailSecurity.Data.fireglass_log.action_reason | String | Reason for the action taken. |
| SymantecEmailSecurity.Data.fireglass_log.text | String | Text description of the event. |
| SymantecEmailSecurity.Data.fireglass_log.rule_id | Number | ID of the rule applied. |
| SymantecEmailSecurity.Data.fireglass_log.rule_name | String | Name of the rule applied. |
| SymantecEmailSecurity.Data.fireglass_log.service | String | Service involved in the event. |
| SymantecEmailSecurity.Data.fireglass_log.mime_type | String | MIME type of the event. |
| SymantecEmailSecurity.Data.fireglass_log.password_supplied | String | Indicates if a password was supplied. |
| SymantecEmailSecurity.Data.fireglass_log.file_type | String | Type of file involved. |
| SymantecEmailSecurity.Data.fireglass_log.content_type | String | Content type of the event. |
| SymantecEmailSecurity.Data.fireglass_log.host | String | Host involved in the event. |
| SymantecEmailSecurity.Data.fireglass_log.geoip_country_name | String | Country name from GeoIP lookup. |
| SymantecEmailSecurity.Data.fireglass_log.top_level_url | String | Top-level URL involved. |
| SymantecEmailSecurity.Data.fireglass_log.response_status_code | Number | HTTP response status code. |
| SymantecEmailSecurity.Data.fireglass_log.resource_type | String | Type of resource involved. |
| SymantecEmailSecurity.Data.fireglass_log.total_bytes | Number | Total bytes transferred. |
| SymantecEmailSecurity.Data.fireglass_log.total_bytes_sent | Number | Total bytes sent. |
| SymantecEmailSecurity.Data.fireglass_log.md5 | String | MD5 hash of the content. |
| SymantecEmailSecurity.Data.fireglass_log.sha256 | String | SHA-256 hash of the content. |
| SymantecEmailSecurity.Data.fireglass_log.file_path | String | File path of the content. |
| SymantecEmailSecurity.Data.fireglass_log.file_name | String | File name of the content. |
| SymantecEmailSecurity.Data.fireglass_log.details | String | Details of the event. |
| SymantecEmailSecurity.Data.fireglass_log.url_risk | Number | Risk score of the URL. |
| SymantecEmailSecurity.Data.fireglass_log.tenant_id | String | Tenant ID associated with the event. |
| SymantecEmailSecurity.Data.fireglass_log.xMsgRef | String | Unique Fireglass message reference. |
| SymantecEmailSecurity.Data.emailInfo.authResults.raw_header | String | Raw authentication results header. |
| SymantecEmailSecurity.Data.emailInfo.authResults.dkim | String | DKIM verification result. |
| SymantecEmailSecurity.Data.emailInfo.authResults.dkim_signing_domain | String | Domain used for DKIM signing. |
| SymantecEmailSecurity.Data.emailInfo.authResults.spf | String | SPF verification result. |
| SymantecEmailSecurity.Data.emailInfo.authResults.dmarc | String | DMARC verification result. |
| SymantecEmailSecurity.Data.emailInfo.authResults.dmarc_policy | String | DMARC policy applied. |
| SymantecEmailSecurity.Data.emailInfo.authResults.dmarc_override_action | String | Action overridden by DMARC policy. |
| SymantecEmailSecurity.Data.incidents.xMsgRef | String | Unique incident message reference. |
| SymantecEmailSecurity.Data.incidents.addressContexts.name | String | Name in incident address context. |
| SymantecEmailSecurity.Data.incidents.addressContexts.domain | String | Domain in incident address context. |
| SymantecEmailSecurity.Data.incidents.addressContexts.isSender | Number | Indicates if address is sender. |
| SymantecEmailSecurity.Data.incidents.severity | String | Severity level of the incident. |
| SymantecEmailSecurity.Data.incidents.securityService | String | Security service involved. |
| SymantecEmailSecurity.Data.incidents.detectionMethod | String | Method used for detection. |
| SymantecEmailSecurity.Data.incidents.verdict | String | Verdict of the incident. |
| SymantecEmailSecurity.Data.incidents.action | String | Action taken for the incident. |
| SymantecEmailSecurity.Data.incidents.reason | String | Reason for the action. |
| SymantecEmailSecurity.Data.incidents.filesAndLinks.nodeType | String | Type of node in incident. |
| SymantecEmailSecurity.Data.incidents.filesAndLinks.fileNameOrURL | String | File name or URL in incident. |
| SymantecEmailSecurity.Data.incidents.filesAndLinks.fileSize | Number | Size of the file in incident. |
| SymantecEmailSecurity.Data.incidents.filesAndLinks.fileType | String | Type of file in incident. |
| SymantecEmailSecurity.Data.incidents.filesAndLinks.md5 | String | MD5 hash of the file. |
| SymantecEmailSecurity.Data.incidents.filesAndLinks.sha256 | String | SHA-256 hash of the file. |
| SymantecEmailSecurity.Data.incidents.filesAndLinks.malwareName | String | Name of the detected malware. |
| SymantecEmailSecurity.Data.incidents.filesAndLinks.malwareCategory | String | Category of the detected malware. |
| SymantecEmailSecurity.Data.incidents.filesAndLinks.urlCategories | Unknown | Categories of URLs in the incident. |
| SymantecEmailSecurity.Data.incidents.filesAndLinks.urlRiskScore | Unknown | Risk score of URLs in the incident. |
| SymantecEmailSecurity.Data.incidents.filesAndLinks.index | Number | Index of the file/link in incident. |
| SymantecEmailSecurity.Data.incidents.filesAndLinks.parentIndex | Number | Parent index of the file/link in incident. |
| SymantecEmailSecurity.Data.incidents.filesAndLinks.xMsgRef | String | Unique incident file message reference. |
| SymantecEmailSecurity.Data.incidents.filesAndLinks.linkSource | String | Source of the link in incident. |
| SymantecEmailSecurity.Data.incidents.dmasDelivered | Unknown | Indicates if DMAS was delivered. |
| SymantecEmailSecurity.Data.incidents.dmasInfo | Unknown | DMAS information related to the incident. |
| SymantecEmailSecurity.Data.attacks.affectedUsers.key | String | Affected user email address. |
| SymantecEmailSecurity.Data.attacks.affectedUsers.value | Number | Number of affected users. |
| SymantecEmailSecurity.Data.attacks.affectedUsers.type | String | Type of affected users. |
| SymantecEmailSecurity.Data.attacks.affectedUsersByDomain.key | String | Domain of affected users. |
| SymantecEmailSecurity.Data.attacks.affectedUsersByDomain.value | Number | Number of affected users by domain. |
| SymantecEmailSecurity.Data.attacks.affectedUsersByDomain.type | String | Type of affected users by domain. |
| SymantecEmailSecurity.Data.attacks.geoIpSources.key | String | GeoIP source country code. |
| SymantecEmailSecurity.Data.attacks.geoIpSources.value | Number | Percentage of attacks from GeoIP source. |
| SymantecEmailSecurity.Data.attacks.geoIpSources.type | String | Type of GeoIP source data. |
| SymantecEmailSecurity.Data.attacks.globalTimeline.key | Date | Date in global attack timeline. |
| SymantecEmailSecurity.Data.attacks.globalTimeline.value | Number | Number of global attacks on date. |
| SymantecEmailSecurity.Data.attacks.globalTimeline.type | String | Type of global timeline data. |
| SymantecEmailSecurity.Data.attacks.ipSources.key | String | IP address of attack source. |
| SymantecEmailSecurity.Data.attacks.ipSources.value | Number | Percentage of attacks from IP source. |
| SymantecEmailSecurity.Data.attacks.ipSources.type | String | Type of IP source data. |
| SymantecEmailSecurity.Data.attacks.localTimeline.key | Date | Date in local attack timeline. |
| SymantecEmailSecurity.Data.attacks.localTimeline.value | Number | Number of local attacks on date. |
| SymantecEmailSecurity.Data.attacks.localTimeline.type | String | Type of local timeline data. |
| SymantecEmailSecurity.Data.attacks.threatNames.key | String | Name of the detected threat. |
| SymantecEmailSecurity.Data.attacks.threatNames.value | Number | Percentage of attacks with this threat. |
| SymantecEmailSecurity.Data.attacks.threatNames.type | String | Type of threat data. |
| SymantecEmailSecurity.Data.attacks.traitImportance.ioc | String | Indicator of compromise. |
| SymantecEmailSecurity.Data.attacks.traitImportance.value | String | Value of the trait. |
| SymantecEmailSecurity.Data.attacks.traitImportance.weight | Number | Weight of the trait. |
| SymantecEmailSecurity.Data.attacks.traitImportance.type | String | Type of trait data. |
| SymantecEmailSecurity.Data.attacks.avgMailboxesGlobal | Number | Average global mailboxes affected. |
| SymantecEmailSecurity.Data.attacks.attackVolumeGlobal | Number | Global volume of attacks. |
| SymantecEmailSecurity.Data.attacks.attackVolumeLocal | Number | Local volume of attacks. |
| SymantecEmailSecurity.Data.attacks.attackedMailboxesGlobal | Number | Number of globally attacked mailboxes. |
| SymantecEmailSecurity.Data.attacks.attackedMailboxesLocal | Number | Number of locally attacked mailboxes. |
| SymantecEmailSecurity.Data.attacks.attackedOrgsGlobal | Number | Number of globally attacked organizations. |
| SymantecEmailSecurity.Data.attacks.attackDescription | String | Description of the attack. |
| SymantecEmailSecurity.Data.attacks.attackType | String | Type of attack. |
| SymantecEmailSecurity.Data.attacks.cluster | String | Cluster identifier for the attack. |
| SymantecEmailSecurity.Data.topAttacked.key | String | Email address of top attacked user. |
| SymantecEmailSecurity.Data.topAttacked.value | Number | Number of attacks on top user. |
| SymantecEmailSecurity.Data.topAttacked.type | String | Type of attack count data. |
| SymantecEmailSecurity.Data.reportWindowStartTime | Number | Start time of the report window. |
| SymantecEmailSecurity.Data.reportWindowEndTime | Number | End time of the report window. |
#### Command example
```!symantec-email-security-data-list```
#### Context Example
```json
{
"SymantecEmailSecurity": {
"Data": [
{
"emailInfo": {
"HELOString": "inbound.000.example",
"authResults": null,
"avQuarantinePenId": "",
"country": "",
"envFrom": "bounce-newaccount-verp-00000000000000000000@eu.quarantine.symantec.com",
"envTo": [
"hello@world"
],
"filesAndLinks": [
{
"fileNameOrURL": "Unknown00000000.data",
"fileSize": 1000,
"fileType": "text/html",
"index": 2,
"linkSource": "BASIC_EMAIL_INFO",
"md5": "00000000000000000000000000000000",
"nodeType": "FILE_INCLUDED",
"parentIndex": 1,
"sha256": "0000000000000000000000000000000000000000000000000000000000000000",
"urlCategories": null,
"urlRiskScore": null
},
{
"fileNameOrURL": "https://www.example.com",
"fileSize": 0,
"fileType": "",
"index": 3,
"linkSource": "BASIC_EMAIL_INFO",
"md5": null,
"nodeType": "LINK_INCLUDED",
"parentIndex": 2,
"sha256": null,
"urlCategories": [
"Technology/Internet"
],
"urlRiskScore": 1
}
],
"headerFrom": "quarantine@eu.quarantine.symantec.com",
"headerReplyTo": "",
"headerTo": [
"hello@world"
],
"isOutbound": false,
"longMsgRef": "server-0.tower-0.messagelabs.com!000!000!0",
"mailProcessingStartTime": 1000000000,
"messageId": "000.000@quarantine.messagelabs.com",
"messageSize": 10000,
"newDomainAge": null,
"rawHeaderFrom": " <bounce-newaccount-verp-00000000000000000000@eu.quarantine.symantec.com>",
"senderIp": "0.0.0.0",
"senderMailserver": "0.0.0.0.googleusercontent.com",
"subject": "New Email Quarantine Account",
"timeInCynicSandboxMs": -1,
"tlsInfo": {
"tlsAdvertised": true,
"tlsCipher": "ECDHE-RSA-AES256-GCM-SHA384",
"tlsFallbackReason": "",
"tlsForwardSecrecy": true,
"tlsKeyLength": 256,
"tlsNegotiationFailed": false,
"tlsPolicy": "OPPORTUNISTIC",
"tlsProtocol": "TLSv1.2",
"tlsUsed": true
},
"xMsgRef": "000"
},
"incidents": [
{
"action": "Block",
"addressContexts": [
{
"domain": "lior.sb",
"isSender": false,
"name": "lior"
}
],
"detectionMethod": "Skeptic Heuristics",
"dmasDelivered": false,
"dmasInfo": [],
"filesAndLinks": [
{
"fileNameOrURL": "message.txt",
"fileSize": 1197,
"fileType": "",
"index": 23,
"linkSource": "INCIDENT",
"malwareCategory": "trojan",
"malwareName": "Test/Eicar",
"md5": "00000000000000000000000000000000",
"nodeType": "FILE_INCLUDED",
"parentIndex": 22,
"sha256": "0000000000000000000000000000000000000000000000000000000000000000",
"urlCategories": null,
"urlRiskScore": null,
"xMsgRef": "000"
},
{
"fileNameOrURL": "message.txt",
"fileSize": 1197,
"fileType": "",
"index": 22,
"linkSource": "INCIDENT",
"malwareCategory": "uncategorized",
"malwareName": "unknown",
"md5": "00000000000000000000000000000000",
"nodeType": "FILE_INCLUDED",
"parentIndex": 0,
"sha256": "0000000000000000000000000000000000000000000000000000000000000000",
"urlCategories": null,
"urlRiskScore": null,
"xMsgRef": "000"
}
],
"reason": "unknown",
"securityService": "Anti-Malware",
"severity": "LOW",
"verdict": "Malware",
"xMsgRef": "000"
}
]
}
]
}
}
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
#### Context Example
```json
{
"SymantecEmailSecurity": {
"EmailQueue": {
"Domains": [
{
"DeliveryQueueCountInbound": 0,
"DeliveryQueueCountOutbound": 0,
"LongestTimeInDeliveryQueueInbound": 0,
"LongestTimeInDeliveryQueueOutbound": 0,
"LongestTimeInReceiveQueueInbound": 0,
"LongestTimeInReceiveQueueOutbound": 0,
"MeanTimeInDeliveryQueueInbound": 0,
"MeanTimeInDeliveryQueueOutbound": 0,
"MeanTimeInReceiveQueueInbound": 0,
"MeanTimeInReceiveQueueOutbound": 0,
"Name": "lior.sb",
"ReceiveQueueCountInbound": 0,
"ReceiveQueueCountOutbound": 0
}
],
"LongestTimeInInbound": 0,
"LongestTimeInOutbound": 0,
"MeanTimeInQueueInbound": 0,
"MeanTimeInQueueOutbound": 0,
"TotalMessagesInbound": 0,
"TotalMessagesOutbound": 0
}
}
}
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
#### Context Example
```json
{
"SymantecEmailSecurity": {
"QuarantineEmail": [
{
"actions": {
"delete_message": true,
"preview_message": true,
"release_message": true,
"view_subject": true
},
"id": "000",
"metadata": {
"email_date_received": 1728206441148,
"email_envelope_recipient": "example@example.com",
"email_envelope_sender": "example@example.com",
"email_is_released": true,
"email_is_viewed": true,
"email_released_to": "recipient",
"email_sender": "Example (example@example.com)",
"email_size": 0,
"email_subject": "a",
"master_recipient": "example@example.com",
"quarantine_info": {
"direction": "inbound",
"quarantine_type": "CI",
"rules": [
"test"
]
},
"quarantine_reason": "CC",
"service_type": "ess",
"user_id": 0
}
},
{
"actions": {
"delete_message": true,
"preview_message": true,
"release_message": true,
"view_subject": true
},
"id": "001",
"metadata": {
"email_date_received": 1728221871295,
"email_envelope_recipient": "example@example.com",
"email_envelope_sender": "example@example.com",
"email_is_released": false,
"email_is_viewed": true,
"email_sender": "Example (example@example.com)",
"email_size": 0,
"email_subject": "a",
"master_recipient": "example@example.com",
"quarantine_info": {
"direction": "inbound",
"quarantine_type": "CI",
"rules": [
"test"
]
},
"quarantine_reason": "CC",
"service_type": "ess",
"user_id": 1
}
},
{
"actions": {
"delete_message": true,
"preview_message": true,
"release_message": true,
"view_subject": true
},
"id": "002",
"metadata": {
"email_date_received": 1728221875373,
"email_envelope_recipient": "example@example.com",
"email_envelope_sender": "example@example.com",
"email_is_released": false,
"email_is_viewed": false,
"email_sender": "Example (example@example.com)",
"email_size": 0,
"email_subject": "a",
"master_recipient": "example@example.com",
"quarantine_info": {
"direction": "inbound",
"quarantine_type": "CI",
"rules": [
"test"
]
},
"quarantine_reason": "CC",
"service_type": "ess",
"user_id": 2
}
},
{
"actions": {
"delete_message": true,
"preview_message": true,
"release_message": true,
"view_subject": true
},
"id": "003",
"metadata": {
"email_date_received": 1728221880677,
"email_envelope_recipient": "example@example.com",
"email_envelope_sender": "example@example.com",
"email_is_released": true,
"email_is_viewed": false,
"email_released_to": "recipient",
"email_sender": "Example (example@example.com)",
"email_size": 0,
"email_subject": "a",
"master_recipient": "example@example.com",
"quarantine_info": {
"direction": "inbound",
"quarantine_type": "CI",
"rules": [
"test"
]
},
"quarantine_reason": "CC",
"service_type": "ess",
"user_id": 3
}
},
{
"actions": {
"delete_message": true,
"preview_message": true,
"release_message": true,
"view_subject": true
},
"id": "004",
"metadata": {
"email_date_received": 1728222011087,
"email_envelope_recipient": "example@example.com",
"email_envelope_sender": "example@example.com",
"email_is_released": false,
"email_is_viewed": false,
"email_sender": "Example (example@example.com)",
"email_size": 0,
"email_subject": "a",
"master_recipient": "example@example.com",
"quarantine_info": {
"direction": "inbound",
"quarantine_type": "CI",
"rules": [
"test"
]
},
"quarantine_reason": "CC",
"service_type": "ess",
"user_id": 4
}
}
]
}
}
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
#### Context Example
```json
{
"SymantecEmailSecurity": {
"Allow": [
{
"description": "Test",
"emailDirection": "I",
"expiryDate": "2024-01-01 00:00:00.0",
"iocBlackListId": "00000000-0000-0000-0000-000000000000",
"iocType": "subject",
"iocValue": "Test",
"remediationAction": "Q",
"status": "Active"
},
{
"description": "url to block",
"emailDirection": "O",
"expiryDate": "2024-01-01 00:00:00.0",
"iocBlackListId": "00000000-0000-0000-0000-000000000000",
"iocType": "url",
"iocValue": "https://www.example.com",
"remediationAction": "H",
"status": "Active"
}
]
}
}
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
#### Context Example
```json
{
"SymantecEmailSecurity": {
"Block": [
{
"description": "Test",
"emailDirection": "I",
"expiryDate": "2024-01-01 00:00:00.0",
"iocBlackListId": "00000000-0000-0000-0000-000000000000",
"iocType": "subject",
"iocValue": "Test",
"remediationAction": "Q",
"status": "Active"
},
{
"description": "url to block",
"emailDirection": "O",
"expiryDate": "2024-01-01 00:00:00.0",
"iocBlackListId": "00000000-0000-0000-0000-000000000000",
"iocType": "url",
"iocValue": "https://www.example.com",
"remediationAction": "H",
"status": "Active"
}
]
}
}
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 - IOCurl_data_feeds— Server URL - Data Feedsurl_email_queue— Server URL - Email Queueurl_quarantine— Server URL - Quarantinecredentials— Usernamequarantine_credentials— Quarantine Usernameproxy— Use system proxy settingsinsecure— Trust any certificate (not secure)isFetch— Fetch incidentsincidentType— Incident typeincidentFetchInterval— Incidents Fetch Intervalmax_fetch— Maximum number of incidents per fetchfirst_fetch— First Fetch Timefetch_type— Fetch Typeseverity— Severity - Email Data Feedtype— Type - Email Data Feedinclude_delivery— Include Delivery - Email Data Feedquery_quarantine— Query - Email Quarantinetype_quarantine— Type - Email Quarantineadmin_domain_quarantine— Admin Domain - mail Quarantine
Commands (15)
-
symantec-email-security-data-listRetrieves 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-listReturns a list of domains owned by the customer, with queue statistics for each domain.
-
symantec-email-security-ioc-actionAdd, update, delete, and renew multiple IOCs through the `entry_id` or a single IOC through the rest of the parameters.
-
symantec-email-security-ioc-listList the IOCs that apply to a specific domain or to all domains.
-
symantec-email-security-ioc-renewRenew 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-listRetrieve the allow list items.
-
symantec-email-security-item-allow-list-deleteAllows 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-updateAllows 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-listRetrieve the block list items.
-
symantec-email-security-item-block-list-deleteAllows 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-updateAllows 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-deleteDeletes 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-listRetrieves 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-previewRetrieves the contents of the email specified in the request. To preview an email the compliance policy must allow it.
-
symantec-email-security-quarantine-email-releaseReleases the set of quarantined emails specified in the request.
import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401, F403 # pylint: disable=unused-wildcard-import """ Imports """ import copy import dataclasses import functools import http from collections.abc import Callable from enum import Enum from typing import Any """ Global Variables """ INTEGRATION_PREFIX = "SymantecEmailSecurity" COMMAND_PREFIX = "symantec-email-security" MAX_INCIDENTS_TO_FETCH = 200 DEFAULT_LIMIT = 50 QUARANTINE_API_MAX_LIMIT = 10000 SEVERITY_MAPPING = { "UNSET_SEVERITY": IncidentSeverity.UNKNOWN, "LOW": IncidentSeverity.LOW, "MEDIUM": IncidentSeverity.MEDIUM, "HIGH": IncidentSeverity.HIGH, "CRITICAL": IncidentSeverity.CRITICAL, } class APIListAction(str, Enum): MERGE = "MERGE" REPLACE = "REPLACE" IOC = "IOC" class APIRowActionChoices(str, Enum): ADD = "A" UPDATE = "U" DELETE = "D" RENEW = "R" class EmailDirectionChoices(str, Enum): INBOUND = "I" OUTBOUND = "O" BOTH = "B" class RemediationActionChoices(str, Enum): BLOCK_AND_DELETE = "B" QUARANTINE = "Q" REDIRECT = "M" TAG_SUBJECT = "T" APPEND_HEADER = "H" class AccessControl(str, Enum): WHITELIST = "whitelist" BLACKLIST = "blacklist" class AccessControlAction(str, Enum): MERGE = "MERGE" DELETE = "DELETE" class SortOrder(str, Enum): DESC = "desc" ASC = "asc" class QuarantineType(str, Enum): SPAM = "SPAM" NEWSLETTER = "NEWSLETTER" CI = "CI" CO = "CO" II = "II" IO = "IO" COMPLIANCE = "COMPLIANCE" DLP = "DLP" @dataclasses.dataclass class IOC: IocType: str | None IocValue: str | None Description: str | None EmailDirection: EmailDirectionChoices | None APIRowAction: APIRowActionChoices | None = None IocBlacklistId: str | None = None RemediationAction: RemediationActionChoices | None = None api_list_action: APIListAction | None = None # Store the action for validation def __post_init__(self): """Automatically validate the instance after it's initialized.""" if self.api_list_action: self.validate(self.api_list_action) # Delete api_list_action from the instance to avoid it being included in serialization del self.api_list_action def validate(self, api_list_action: APIListAction): """Validate the IOC based on the APIListAction and APIRowAction.""" mandatory_fields = [self.IocType, self.IocValue, self.Description, self.EmailDirection] # Check that all mandatory fields are present if not all(mandatory_fields): raise DemistoException("Fields IocType, IocValue, Description, and EmailDirection are mandatory.") # Validate based on the APIListAction (MERGE, REPLACE, IOC) if api_list_action in [APIListAction.MERGE, APIListAction.REPLACE]: self._validate_merge_or_replace(api_list_action) elif api_list_action == APIListAction.IOC: self._validate_ioc() # Validate based on the specific APIRowAction if provided if self.APIRowAction: self._validate_row_action(self.APIRowAction) def _validate_merge_or_replace(self, api_list_action: APIListAction) -> None: """Validate for MERGE and REPLACE actions.""" # Ensure APIRowAction and IocBlacklistId are not present if self.APIRowAction or self.IocBlacklistId: raise DemistoException( f"APIRowAction and IocBlacklistId should be omitted or blank for {api_list_action.value} requests." ) def _validate_ioc(self) -> None: """Validate for the IOC action.""" # Validation based on APIRowAction if not self.APIRowAction: raise DemistoException("APIRowAction must be present for action=ioc.") if self.APIRowAction == APIRowActionChoices.ADD: self._validate_add() elif not self.IocBlacklistId: # For UPDATE, DELETE, and RENEW actions, IocBlacklistId must be present raise DemistoException( f"IocBlacklistId must be present for APIRowAction={self.APIRowAction and self.APIRowAction.value}." ) def _validate_row_action(self, api_row_action: APIRowActionChoices) -> None: """Validate rules based on the APIRowAction.""" validation_map: dict[APIRowActionChoices, Callable[[], None]] = { APIRowActionChoices.ADD: self._validate_add, } | dict.fromkeys( [ APIRowActionChoices.UPDATE, APIRowActionChoices.DELETE, APIRowActionChoices.RENEW, ], self._validate_update_or_delete_or_renew, ) validation_func = validation_map.get(api_row_action) if not validation_func: raise DemistoException(f"Unsupported APIRowAction: {api_row_action}") validation_func() def _validate_add(self) -> None: """Validate for the ADD APIRowAction.""" if self.IocBlacklistId: raise DemistoException("IocBlacklistId should not be present for APIRowAction=A (Add).") def _validate_update_or_delete_or_renew(self) -> None: """Validate for the UPDATE APIRowAction.""" if not self.IocBlacklistId: raise DemistoException( f"IocBlacklistId must be present for APIRowAction={self.APIRowAction and self.APIRowAction.value}" f" ({APIRowActionChoices(self.APIRowAction)})." ) @staticmethod def _convert_to_enum(value: Any, expected_type: type) -> Enum | Any: """Convert value to Enum if expected_type is an Enum or Optional Enum.""" enum_type = None # Handle Enum and None | Enum type using `__args__` if isinstance(expected_type, type) and issubclass(expected_type, Enum): enum_type = expected_type elif args := getattr(expected_type, "__args__", []): # Check if it's a `None | Enum` type enum_type = next( (t for t in args if isinstance(t, type) and issubclass(t, Enum)), None, ) # Convert value to Enum if applicable if enum_type and isinstance(value, str): try: return enum_type(value) except ValueError: raise DemistoException(f"{value} is not a valid {enum_type.__name__}") return value @classmethod def from_dict(cls, env: dict, api_list_action: APIListAction) -> "IOC": """Creates an instance of the IOC class from a dictionary, converting dictionary values to Enum members where applicable. """ field_types = {f.name: f.type for f in dataclasses.fields(cls)} processed_env = { key: cls._convert_to_enum(value, field_types[key]) # type: ignore[arg-type] for key, value in env.items() if key in field_types } ioc = cls(**processed_env) # type: ignore[arg-type] # Doesn't recognize arguments typing in pre-commit ioc.validate(api_list_action) return ioc """ Decorators """ def pagination(items_key: str) -> Callable: """Pagination decorator wrapper to control functionality within the decorator. Args: items_key (str): A key to the inner list of items. Returns: Callable: Pagination decorator. """ def dec(func: Callable) -> Callable: """Pagination decorator holding the callable function. Args: func (Callable): API request for GET command. Returns: Callable: inner function that handles the pagination request. """ def _manual(self, page: int, page_size: int = DEFAULT_LIMIT, *args, **kwargs) -> dict[str, Any]: page = max(page, 1) start_index = (page - 1) * page_size page_size = min(page_size, QUARANTINE_API_MAX_LIMIT) demisto.debug(f"Making manual pagination call with {start_index=}, {page_size=}.") return func(self, start_index=start_index, page_size=page_size, *args, **kwargs) def _automatic(self, limit: int = DEFAULT_LIMIT, *args, **kwargs) -> dict[str, Any]: response: dict[str, Any] = {} remaining_items = limit start_index = None demisto.debug("Starting automatic pagination...") # Keep calling the API until the required amount of items have been met. while remaining_items > 0: page_size = min(remaining_items, QUARANTINE_API_MAX_LIMIT) demisto.debug(f"Making call with {start_index=}, {page_size=}.") current_response = func(self, start_index=start_index, page_size=page_size, *args, **kwargs) # Initialize response on the first call, preserving all outer fields if not response: demisto.debug("Got first response from API.") response = copy.deepcopy(current_response) # Copy to avoid overwriting current_response's key. response[items_key] = [] items = current_response.get(items_key, []) response[items_key] += items received_items = len(items) demisto.debug(f"Received {received_items} from the response.") # API exhausted, no items returned or number of items returned is lower than requested. if not items or received_items < page_size: demisto.debug("Ending automatic pagination, no items were returned or received less than requested.") break # Calculate the start_index and limit for the next run. remaining_items -= received_items start_index = (start_index or 0) + received_items demisto.debug(f"Next run: {remaining_items=}, {start_index=}.") return response @functools.wraps(func) def wrapper( self, page: int | None = None, page_size: int | None = None, limit: int = DEFAULT_LIMIT, *args, **kwargs, ) -> dict[str, Any]: """Handle pagination arguments to return multiple response from an API. Args: page (int | None, optional): Page number to return. Defaults to None. page_size (int | None, optional): Number of items to return in a page. Defaults to None. limit (int, optional): Number of items to return. Defaults to DEFAULT_LIMIT. Returns: dict[str, Any]: Paginated response. """ if page is not None: return _manual(self, page, page_size or DEFAULT_LIMIT, *args, **kwargs) return _automatic(self, limit, *args, **kwargs) return wrapper return dec def validate_response(func: Callable) -> Callable: """Validate the response's status from the API and raise an error in case of failure. Args: func (Callable): API request to validate. """ @functools.wraps(func) def wrapper(*args, **kwargs) -> dict[str, Any]: """Validate the response's status from the API and raise an error in case of failure. Raises: DemistoException: The response status wasn't SUCCESS. Returns: dict[str, Any]: The original API response. """ response = func(*args, **kwargs) if response.get("status") != "SUCCESS": raise DemistoException(f"The API request failed for the following reason: {response}", res=response) return response return wrapper """ Client """ class Client(BaseClient): """Client class to interact with the Symantec email security API.""" def __init__( self, base_url: str, username: str, password: str, verify: bool = True, proxy: bool = False, ) -> None: """Initialize the Client class. Args: base_url (str): The base URL of API. username (str): The username used for authentication. password (str): The password used for authentication. verify (bool, optional): Whether to verify the SSL certificate. Defaults to True. proxy (bool, optional): Whether to use a proxy. Defaults to False. """ super().__init__( base_url=base_url, auth=(username, password), verify=verify, proxy=proxy, headers={"Accept": "application/json"}, ) def list_ioc(self, domain: str = "global") -> list[dict[str, Any]]: """Download the list of IOCs that apply to a specific domain or to all domains. Args: domain (str): Run the command for a specific domain or all domains with 'global'. Defaults to "global". Returns: list[dict[str, Any]]: The API response. """ return self._http_request("GET", url_suffix=f"domains/{domain}/iocs/download") def action_ioc( self, iocs: list[IOC], domain: str = "global", api_list_action: APIListAction = APIListAction.IOC, ) -> list[dict[str, Any]]: """Add, update, delete and renew multiple IOCs. Args: iocs (list[IOC]): List of IOCs to set the action upon. domain (str): Run the command for a specific domain or all domains with 'global'. Defaults to "global". api_list_action (str, optional): Defines the action for IOCs: - MERGE: to merge or update IOCs without APIRowAction and IocBlacklistId. - REPLACE: to delete and replace IOCs without APIRowAction and IocBlacklistId; - IOC: to add (without IocBlacklistId), update, delete, or renew (with IocBlacklistId) IOCs based on APIRowAction. Defaults to "IOC". Returns: list[dict[str, Any]]: The API response. """ return self._http_request( "POST", url_suffix=f"domains/{domain}/iocs/upload", params={"api-list-action": api_list_action.value}, json_data=remove_empty_elements([dataclasses.asdict(ioc) for ioc in iocs]), ) def renew_ioc(self, domain: str = "global") -> None: """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. Args: domain (str): Run the command for a specific domain or all domains with 'global'. Defaults to "global". """ response: requests.Response = self._http_request( "POST", url_suffix=f"domains/{domain}/iocs/renewall", resp_type="response", ) if response.headers.get("x-status") != "SUCCESS": raise DemistoException(f"Failed to renew IOCs, reason: {response.headers.get('x-diagnostics-info')}.") def list_data( self, feed_type: str, reset: str | None = None, include: str | None = None, ) -> str | list[dict[str, Any]]: """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. - ec-reports: contextual information about emails blocked by Anti-Malware service. Args: feed_type (str): The name of the data feed to retrieve. reset (str, optional): A string representing the date from which to start reading metadata with the format YYYY-MM-ddThh:mm:ssZ. When calling the service for the first time, if you don't provide the reset option a 416 status code will be returned. The reset request itself returns a 200 status code, but no data items. Requests following the initial reset request will return the latest data. For example, using the URI https://datafeeds.emailsecurity.symantec.com/all?reset=2016-09-01T00:00:00Z would reset the cursor for the all feed to midnight on the first of September 2016 (UTC) and start returning data from that point onward. Default to None. include (str, optional): 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. Defaults to None. Returns: dict[str, Any]: The API response. """ return self._http_request( "GET", url_suffix=feed_type, params=remove_empty_elements({"reset": reset, "include": include}), resp_type="text" if reset else "json", ) def list_email_queue(self, domains: list[str] | None = None) -> dict[str, Any]: """Returns a list of domains owned by the customer, with queue statistics for each domain. Args: domains (list[str] | None, optional): Limit responses to only contain results for provided domain. This argument can be repeated to specify multiple domains. Defaults to None. Returns: dict[str, Any]: The API response. """ return self._http_request("GET", url_suffix="stats", params=assign_params(domain=domains)) """ Quarantine Client """ class QuarantineClient(BaseClient): """Client class to interact with the Symantec email security quarantine API.""" def __init__( self, base_url: str, username: str, password: str, verify: bool = True, proxy: bool = False, ) -> None: """Initialize the Client class. Args: base_url (str): The base URL of API. username (str): The username used for authentication. password (str): The password used for authentication. verify (bool, optional): Whether to verify the SSL certificate. Defaults to True. proxy (bool, optional): Whether to use a proxy. Defaults to False. """ super().__init__( base_url=base_url, auth=(username, password), verify=verify, proxy=proxy, ) @pagination("mail_list") @validate_response def list_quarantine_email( self, q: str | None = None, sort_column: str | None = None, sort_order: str | None = None, after: str | None = None, before: str | None = None, page_size: int | None = None, start_index: int | None = None, filter_type: str | None = None, include_deleted: str | None = None, user: str | None = None, admin_domain: str | None = None, ) -> dict[str, Any]: """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. Args: q (str | None, optional): 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''. Defaults to None. sort_column (str | None, optional): Specifies the column to use for sorting. Defaults to None. sort_order (str | None, optional): Specifies the order in which to sort. Defaults to None. after (str, optional): A Unix time stamp value in milliseconds that specifies that the API selects only emails that were quarantined after this time. Defaults to None. before (str | None, optional): A Unix time stamp value in milliseconds, to select only emails that were quarantined before this time. Defaults to None. page_size (int | None, optional): Number of entries to be returned in a response. Defaults to None. start_index (int | None, optional): The start index of the results. Defaults to None. filter_type (str | None, optional): A string used to filter emails based on the quarantine type. By default includes the emails quarantined for all types. Accepted values are: SPAM, NEWSLETTER, CI, CO, II, IO, COMPLIANCE: Includes Content control, DLP and Image control emails. DLP: Includes only DLP emails. Defaults to None. include_deleted (str, optional): Specifies whether to include items marked as deleted in the search results. Allowed values are YES and NO. Defaults to None user (str | None, optional): An email address. Returns only the quarantined emails of the user whose email address is specified. Defaults to None. admin_domain (str, optional): A string identifying a 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. Defaults to None. Returns: dict[str, Any]: The API response. """ return self._http_request( "GET", url_suffix="v1/mails", params=remove_empty_elements( { "q": q, "sort_column": sort_column, "sort_order": sort_order, "after": after, "before": before, "page_size": page_size, "start_index": start_index, "filter_type": filter_type, "include_deleted": include_deleted, "user": user, "admin_domain": admin_domain, } ), ) @validate_response def preview_quarantine_email(self, q: str) -> dict[str, Any]: """Retrieves the contents of the email specified in the request. To preview an email the compliance policy must allow it. Args: q (str): The message ID of the email to preview. Returns: dict[str, Any]: The API response. """ return self._http_request("GET", url_suffix="v1/mails/preview", params={"q": q}) @validate_response def release_quarantine_email( self, mail_list: list[str], recipient: str | None = None, headers: list[str] | None = None, encrypt: str | None = None, ) -> dict[str, Any]: """Releases the set of emails specified in the request. Args: mail_list (list[str]): List of emails message IDs to release. recipient (str | None, optional): An email address to which the mails have to be released instead of the recipient users address. Defaults to None. recipient (str | None, optional): List of x-headers that will be added to the message on release. Defaults to None. recipient (str | None, optional): If true adds an 'x-encrypted-quarantine-release: true' to the released email. Customers have to configure a corresponding DP rule that triggers encryption. Defaults to None. Returns: dict[str, Any]: The API response. """ return self._http_request( "POST", url_suffix="v1/mails/release", json_data=remove_empty_elements( { "mail_list": mail_list, "options": { "recipient": recipient, "headers": {f"x-header-{i + 1}": header for i, header in enumerate(headers or [])}, "encrypt": encrypt, }, } ), ) @validate_response def delete_quarantine_email(self, message_ids: list[str]) -> None: """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. Args: message_ids (list[str]): List of emails message IDs to delete. Returns: dict[str, Any]: The API response. """ return self._http_request( "POST", url_suffix="v1/mails/delete", json_data=message_ids, ) @pagination("items") @validate_response def list_item_allow_block_list( self, access_control: AccessControl, q: str | None = None, sort_column: str | None = None, sort_order: str | None = None, from_date: str | None = None, to_date: str | None = None, start_index: int | None = None, page_size: int | None = None, ) -> dict[str, Any]: """Retrieve the allow/block list items. Args: access_control (AccessControl): The access control list to retrieve. q (str | None, optional): A string that at least some part of the allow/block list item must contain. Defaults to None. sort_column (str | None, optional): Specifies the column to use for sorting. Defaults to None. sort_order (str | None, optional): Specifies the order in which to sort. Defaults to None. from_date (str, optional): A Unix time stamp value used to select only SUDULS items that were created after this time. Defaults to None. to_date (str | None, optional): A Unix time stamp value used to select only SUDULS items that were created before this time. Defaults to None. start_index (int | None, optional): Starting entry index of the page. Defaults to None. page_size (int | None, optional): Number of entries to be returned in the response. Defaults to None. Returns: dict[str, Any]: The API response. """ return self._http_request( "GET", url_suffix=f"v1/users/{access_control}", params=remove_empty_elements( { "q": q, "sort_column": sort_column, "sort_order": sort_order, "from_date": from_date, "to_date": to_date, "start_index": start_index, "page_size": page_size, } ), ) @validate_response def action_item_allow_block_list( self, access_control: AccessControl, action: AccessControlAction, suduls_user: str | None = None, suduls_item_id: str | None = None, email_or_domain: str | None = None, description: str | None = None, ) -> dict[str, Any]: """Allows a SUDULS user to add a new item to allow/block list, or to update/delete an existing item. Args: access_control (AccessControl): Path param that dictates whether the command is whitelist/blacklist. action (AccessControlAction): The action to take upon the allow/block list item. suduls_user (str): Email address of the user for whom the entry should be added in the allow/block list. suduls_item_id (str | None, optional): ID of SUDULS item to be added/updated/deleted. Not required when adding an item. Defaults to None. email_or_domain (str | None, optional): Email address or domain to be added in the allow/block list. Defaults None. description (str | None, optional): Description of the item to be added to the allow/block list. Defaults None. Returns: dict[str, Any]: The API response. """ return self._http_request( "POST", url_suffix=f"v1/users/{access_control}", json_data=remove_empty_elements( { "suduls_user": suduls_user, "suduls_itemId": suduls_item_id, "action": action, "email_or_domain": email_or_domain, "description": description, } ), ) """ Helpers """ def determine_clients( command: str, username: str | None, password: str | None, command_to_url: dict[str, Any], has_any_client_url: bool, quarantine_username: str | None, quarantine_password: str | None, url_quarantine: str | None, verify_certificate: bool, proxy: bool, ) -> tuple[Client | None, QuarantineClient | None]: """Determines and returns the appropriate client(s) for executing a command. Args: command (str): The command to be executed, mapped to a specific base URL. username (str | None): The username for regular client authentication. password (str | None): The password for regular client authentication. command_to_url (dict[str, Any]): A dictionary mapping commands to their respective base URLs. quarantine_username (str | None): The username for quarantine client authentication. quarantine_password (str | None): The password for quarantine client authentication. url_quarantine (str | None): The base URL for the quarantine client. verify_certificate (bool): Whether to verify the server's SSL certificate. proxy (bool): Whether to use a proxy when making requests. Raises: DemistoException: - Raised if only one of username/password or quarantine_username/quarantine_password is provided. - Raised if the URL of specific credentials weren't provided. Returns: tuple[Client | None, QuarantineClient | None]: A tuple containing: - A `Client` instance if regular credentials and a URL were provided, otherwise `None`. - A `QuarantineClient` instance if quarantine credentials and a URL were provided, otherwise `None`. """ if bool(username) != bool(password) or bool(quarantine_username) != bool(quarantine_password): raise DemistoException("Both username and password must be present when adding credentials.") if not any((username, password, quarantine_username, quarantine_password)): raise DemistoException("At least one of the credentials must be filled.") client = None quarantine_client = None is_test_command = command == "test-module" if username and password and (is_test_command or command in command_to_url): if base_url := command_to_url.get(command): client = Client( base_url=base_url, username=username, password=password, verify=verify_certificate, proxy=proxy, ) elif not (is_test_command and has_any_client_url): raise DemistoException( "Missing URL for 'Credentials', please fill the correct URL according to the mapping in 'Help'." ) if quarantine_username and quarantine_password: if not url_quarantine: raise DemistoException("Missing URL for 'Quarantine Credentials', please fill 'Server URL - Quarantine'.") quarantine_client = QuarantineClient( base_url=url_quarantine, username=quarantine_username, password=quarantine_password, verify=verify_certificate, proxy=proxy, ) return client, quarantine_client def convert_datetime_string(dt_str: str | datetime) -> str: """Converts a datetime string to ISO 8601 format with microseconds set to zero and appends 'Z'. Args: dt_str (str | datetime): The datetime string to convert. Returns: str: The converted datetime string in ISO 8601 format with 'Z' appended. """ dt = cast(datetime, arg_to_datetime(dt_str, required=True)) if not isinstance(dt_str, datetime) else dt_str dt = dt.replace(microsecond=0) # Remove timezone information if present if dt.tzinfo is not None: dt = dt.astimezone(timezone.utc).replace(tzinfo=None) return dt.isoformat() + "Z" def convert_to_epoch_timestamp(dt_str: datetime | str | None) -> str | None: """Converts a datetime string to an epoch timestamp in milliseconds. Args: dt_str (str | None): The datetime string to convert. Returns: str: If a valid date string was given, then an epoch timestamp, otherwise None. """ dt = arg_to_datetime(dt_str) if not isinstance(dt_str, datetime) else dt_str if not dt: return None return str(int(dt.timestamp() * 1000)) def arg_to_optional_bool(arg: Any | None) -> None | bool: """Converts an argument to an optional boolean value. Args: arg (Any | None): The argument to be converted. Can be of any type or None. Returns: None | bool: Returns None if the argument is None; otherwise, returns the boolean representation of the arg. """ return None if arg is None else argToBoolean(arg) """ Commands """ @logger def test_module( credentials: tuple | None = None, url_ioc: str | None = None, url_data_feeds: str | None = None, url_email_queue: str | None = None, quarantine_client: QuarantineClient | None = None, verify: bool = False, proxy: bool = False, ) -> str: """Test the connection to the API only for clients that are present. Args: client (Client): Session to the API to run HTTP requests. quarantine_client (QuarantineClient): Session to the API to run HTTP requests. Raises: DemistoException: When an unknown HTTP error has occurred. Returns: str: returns "ok" which represents that the test connection to the client was successful. Otherwise, return an informative message based on the user's input. """ if not any((credentials, quarantine_client)): return "At least one of the credentials must be filled." client_passed = False try: if credentials: username, password = credentials if url_ioc: try: Client(url_ioc, username=username, password=password, verify=verify, proxy=proxy).list_ioc() except DemistoException as exc: if exc.res and exc.res.status_code == http.HTTPStatus.NOT_FOUND: return "The given URL for 'Server URL - IOC' is invalid. Please verify the URL." raise exc if url_data_feeds: try: Client(url_data_feeds, username=username, password=password, verify=verify, proxy=proxy).list_data( "all", convert_datetime_string("3 days") ) except DemistoException as exc: if exc.res and exc.res.status_code == http.HTTPStatus.NOT_FOUND: return "The given URL for 'Server URL - Data Feeds' is invalid. Please verify the URL." raise exc if url_email_queue: try: Client(url_email_queue, username=username, password=password, verify=verify, proxy=proxy).list_email_queue() except DemistoException as exc: if exc.res and exc.res.status_code == http.HTTPStatus.NOT_FOUND: return "The given URL for 'Server URL - Email Queue' is invalid. Please verify the URL." raise exc client_passed = True if quarantine_client: try: quarantine_client.list_quarantine_email() except DemistoException as exc: if exc.res and exc.res.status_code == http.HTTPStatus.NOT_FOUND: return "The given URL for 'Server URL - Quarantine' is invalid" raise exc except DemistoException as exc: if exc.res is not None and exc.res.status_code == http.HTTPStatus.UNAUTHORIZED: return ( "Authorization Error: Invalid Credentials." f" Please verify the {'Quarantine ' if client_passed else ''}credentials." ) raise exc return "ok" @logger def list_ioc_command(client: Client, args: dict[str, Any]) -> CommandResults: """List the IOCs that apply to a specific domain or to all domains. Args: client (Client): A session to run HTTP requests to the API. args (dict[str, Any]): Arguments passed down by the CLI to configure the request. Returns: CommandResults: Outputs of the command that represent an entry in the warroom. """ raw_response = client.list_ioc(args.get("domain", "global")) if not argToBoolean(args.get("all_results", False)): limit = arg_to_number(args.get("limit", 50)) raw_response = raw_response[:limit] table = [ { "ID": item.get("iocBlackListId"), "Type": item.get("iocType"), "Value": item.get("iocValue"), "Status": item.get("status"), "Description": item.get("description"), "Email Direction": ( EmailDirectionChoices(item["emailDirection"]).name.lower() if item.get("emailDirection") else None ), "Remediation Action": ( RemediationActionChoices(item["remediationAction"]).name.lower().replace("_", " ") if item.get("remediationAction") else None ), "Expiry Date": item.get("expiryDate"), } for item in raw_response ] readable_output = tableToMarkdown( name="IOC(s)", t=table, headers=[ "ID", "Type", "Value", "Status", "Description", "Email Direction", "Remediation Action", "Expiry Date", ], removeNull=True, ) return CommandResults( outputs_prefix=f"{INTEGRATION_PREFIX}.IOC", outputs_key_field="iocBlackListId", outputs=raw_response, readable_output=readable_output, raw_response=raw_response, ) @logger def action_ioc_command(client: Client, args: dict[str, Any]) -> CommandResults: """Add, update, delete and renew multiple IOCs. Args: client (Client): A session to run HTTP requests to the API. args (dict[str, Any]): Arguments passed down by the CLI to configure the request. Returns: CommandResults: Outputs of the command that represent an entry in the warroom. """ domain = args.get("domain", "global") action = "IOC" if args["action"] == "upload_ioc_json" else args["action"].upper() api_row_action = None if action in APIListAction.__members__: api_list_action = APIListAction[action] else: # action in APIRowActionChoices api_list_action = APIListAction.IOC api_row_action = APIRowActionChoices[action] iocs: list[IOC] = [] if entry_id := args.get("entry_id"): # Build IOCs from an entry file. if api_row_action: raise DemistoException("The field `entry_id` is only compatible with `action=merge/replace/ioc`.") file_entry = demisto.getFilePath(entry_id) with open(file_entry["path"], "rb") as handler: content = handler.read() iocs = [IOC.from_dict(ioc, api_list_action) for ioc in json.loads(content)] else: # Build a single IOC from the given params. if action == APIListAction.IOC: raise DemistoException("`action=ioc` is only compatible with `entry_id`.") if email_direction := args.get("email_direction"): email_direction = EmailDirectionChoices[email_direction.upper()].value if remediation_action := args.get("remediation_action"): remediation_action = RemediationActionChoices[remediation_action.replace(" ", "_").upper()].value iocs.append( IOC( IocBlacklistId=args.get("ioc_id"), APIRowAction=api_row_action, IocType=args.get("ioc_type"), IocValue=args.get("ioc_value"), Description=args.get("description"), EmailDirection=email_direction, RemediationAction=remediation_action, api_list_action=api_list_action, ) ) raw_response = client.action_ioc( iocs=iocs, domain=domain, api_list_action=api_list_action, ) readable_output = "## The following IOC(s) failed:" if raw_response else "## All IOC(s) were uploaded successfully." for item in raw_response: identifier = item.get("iocBlackListId") or f"{item.get('iocType')}-{item.get('iocValue')}" readable_output += f"\n- {identifier}: {item.get('failureReason')}" return CommandResults(readable_output=readable_output) @logger def renew_ioc_command(client: Client, args: dict[str, Any]) -> CommandResults: """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. Args: client (Client): A session to run HTTP requests to the API. args (dict[str, Any]): Arguments passed down by the CLI to configure the request. Returns: CommandResults: Outputs of the command that represent an entry in the warroom. """ client.renew_ioc(args.get("domain", "global")) return CommandResults(readable_output="## All IOC(s) were renewed.") @logger def list_data_command(client: Client, args: dict[str, Any]) -> CommandResults: """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. - ec-reports: contextual information about emails blocked by Anti-Malware service. Args: client (Client): A session to run HTTP requests to the API. args (dict[str, Any]): Arguments passed down by the CLI to configure the request. Returns: CommandResults: Outputs of the command that represent an entry in the warroom. """ feed_type = args.get("feed_type", "all") # Reset data feed timer to given start time. client.list_data( feed_type=feed_type, reset=convert_datetime_string(args.get("start_from", "3 days")), ) # Fetch email data feed from start time. raw_response = cast( list[dict[str, Any]], client.list_data( feed_type=feed_type, include="delivery" if feed_type == "all" and argToBoolean(args.get("include_delivery", False)) else None, ), ) if raw_response: if argToBoolean(args.get("fetch_only_incidents", False)): raw_response = [item for item in raw_response or [] if item.get("incidents")] if not argToBoolean(args.get("all_results", False)): limit = arg_to_number(args.get("limit", 50)) raw_response = raw_response[:limit] table = [] for item in raw_response or []: row: dict[str, Any] = {"Incidents": []} if email_info := item.get("emailInfo"): row["Message Size"] = email_info.get("messageSize") row["Subject"] = email_info.get("subject") row["Envelope From"] = email_info.get("envFrom") row["Envelope To"] = email_info.get("envTo") row["Sender IP"] = email_info.get("senderIp") row["Sender Mail Server"] = email_info.get("senderMailserver") row["File/URLs With Risk"] = [ f"{v.get('fileNameOrURL')}-{v.get('urlRiskScore')}" for v in email_info.get("filesAndLinks", []) ] for incident in item.get("incidents") or []: # The key itself may contain null value. row["Incidents"].append( { "Severity": incident.get("severity"), "Security Service": incident.get("securityService"), "Detection Method": incident.get("detectionMethod"), "Verdict": incident.get("verdict"), "Action": incident.get("action"), } ) table.append(row) readable_output = tableToMarkdown( name="Email Data Feed(s)", t=table, headers=[ "Message Size", "Subject", "Envelope From", "Envelope To", "Sender IP", "Sender Mail Server", "File/URLs With Risk", "Incidents", ], removeNull=True, ) return CommandResults( outputs_prefix=f"{INTEGRATION_PREFIX}.Data", outputs=raw_response, readable_output=readable_output, raw_response=raw_response, ) @logger def list_email_queue_command(client: Client, args: dict[str, Any]) -> CommandResults: """Returns a list of domains owned by the customer, with queue statistics for each domain. Args: client (Client): A session to run HTTP requests to the API. args (dict[str, Any]): Arguments passed down by the CLI to configure the request. Returns: CommandResults: Outputs of the command that represent an entry in the warroom. """ raw_response = client.list_email_queue(argToList(args.get("domains"))) domains = raw_response.get("Domains") readable_output = tableToMarkdown( name="Email Queue Statistic(s)", t=raw_response, headerTransform=string_to_table_header, headers=[ "TotalMessagesInbound", "TotalMessagesOutbound", "MeanTimeInQueueInbound", "MeanTimeInQueueOutbound", "LongestTimeInInbound", "LongestTimeInOutbound", ], removeNull=True, ) if not argToBoolean(args.get("all_results", False)) and domains: limit = arg_to_number(args.get("limit", 50)) raw_response["Domains"] = domains = domains[:limit] if domains: readable_output += "\n" + tableToMarkdown( name="Domain Statistic(s)", t=domains, headerTransform=string_to_table_header, headers=[ "Name", "ReceiveQueueCountInbound", "ReceiveQueueCountOutbound", "DeliveryQueueCountInbound", "DeliveryQueueCountOutbound", ], removeNull=True, ) return CommandResults( outputs_prefix=f"{INTEGRATION_PREFIX}.EmailQueue", outputs=raw_response, readable_output=readable_output, raw_response=raw_response, ) @logger def list_quarantine_email_command(client: QuarantineClient, args: dict[str, Any]) -> CommandResults: """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. Args: client (QuarantineClient): A session to run HTTP requests to the API. args (dict[str, Any]): Arguments passed down by the CLI to configure the request. Returns: CommandResults: Outputs of the command that represent an entry in the warroom. """ raw_response = client.list_quarantine_email( q=args.get("query"), sort_column=args.get("sort_column"), sort_order=args.get("sort_order", SortOrder.DESC.value), after=convert_to_epoch_timestamp(args.get("after")), before=convert_to_epoch_timestamp(args.get("before")), filter_type=args.get("filter_type"), include_deleted="YES" if arg_to_optional_bool(args.get("include_deleted")) else "NO", user=args.get("user_email"), admin_domain=args.get("admin_domain"), limit=arg_to_number(args.get("limit", DEFAULT_LIMIT), required=True), page=arg_to_number(args.get("page")), page_size=arg_to_number(args.get("page_size")), ) outputs = raw_response.get("mail_list", []) table = [ remove_empty_elements( { "ID": item.get("id"), "Date Received": str(arg_to_datetime(dict_safe_get(item, ["metadata", "email_date_received"]))), "Direction": dict_safe_get(item, ["metadata", "quarantine_info", "direction"]), "Quarantine Type": dict_safe_get(item, ["metadata", "quarantine_info", "quarantine_type"]), "Is Released": dict_safe_get(item, ["metadata", "email_is_released"]), "Quarantine Reason": dict_safe_get(item, ["metadata", "quarantine_reason"]), "Sender": dict_safe_get(item, ["metadata", "email_sender"]), "Master Recipient": dict_safe_get(item, ["metadata", "master_recipient"]), "Subject": dict_safe_get(item, ["metadata", "email_subject"]), } ) for item in outputs ] readable_output = tableToMarkdown( name="Quarantine Email(s)", t=table, headers=[ "ID", "Date Received", "Direction", "Quarantine Type", "Is Released", "Quarantine Reason", "Sender", "Master Recipient", "Subject", ], removeNull=True, ) return CommandResults( outputs_prefix=f"{INTEGRATION_PREFIX}.QuarantineEmail", outputs_key_field="id", outputs=outputs, readable_output=readable_output, raw_response=raw_response, ) @logger def preview_quarantine_email_command(client: QuarantineClient, args: dict[str, Any]) -> CommandResults: """Retrieves the contents of the email specified in the request. To preview an email the compliance policy must allow it. Args: client (QuarantineClient): A session to run HTTP requests to the API. args (dict[str, Any]): Arguments passed down by the CLI to configure the request. Returns: CommandResults: Outputs of the command that represent an entry in the warroom. """ message_id = args["message_id"] raw_response = client.preview_quarantine_email(message_id) outputs = raw_response.get("details", {}) outputs["message_id"] = message_id readable_output = tableToMarkdown( name="Quarantine Email Preview", t=outputs.get("headers", {}), headerTransform=string_to_table_header, headers=[ "date", "from", "to", "subject", ], ) if attachments := outputs.get("attachments"): readable_output += tableToMarkdown( name="Attachments", t=attachments, headerTransform=string_to_table_header, headers=[ "name", "type", ], ) if bodypart := outputs.get("bodypart"): readable_output += tableToMarkdown( name="Body Parts", t=bodypart, headerTransform=string_to_table_header, headers=[ "content", ], ) return CommandResults( outputs_prefix=f"{INTEGRATION_PREFIX}.QuarantineEmailPreview", outputs_key_field="message_id", outputs=outputs, readable_output=readable_output, raw_response=raw_response, ) @logger def release_quarantine_email_command(client: QuarantineClient, args: dict[str, Any]) -> CommandResults: """Releases the set of quarantined emails specified in the request. Args: client (QuarantineClient): A session to run HTTP requests to the API. args (dict[str, Any]): Arguments passed down by the CLI to configure the request. Returns: CommandResults: Outputs of the command that represent an entry in the warroom. """ client.release_quarantine_email( mail_list=argToList(args["message_ids"]), recipient=args.get("recipient"), headers=argToList(args.get("headers")), encrypt=arg_to_optional_bool(args.get("encrypt")), ) return CommandResults(readable_output="## Successfully released all messages.") @logger def delete_quarantine_email_command(client: QuarantineClient, args: dict[str, Any]) -> CommandResults: """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. Args: client (QuarantineClient): A session to run HTTP requests to the API. args (dict[str, Any]): Arguments passed down by the CLI to configure the request. Returns: CommandResults: Outputs of the command that represent an entry in the warroom. """ client.delete_quarantine_email(argToList(args["message_ids"])) return CommandResults(readable_output="## Successfully deleted all messages.") @logger def list_item_allow_block_command(client: QuarantineClient, args: dict[str, Any]) -> CommandResults: """Retrieve the allow/block list items. Args: client (QuarantineClient): A session to run HTTP requests to the API. args (dict[str, Any]): Arguments passed down by the CLI to configure the request. Returns: CommandResults: Outputs of the command that represent an entry in the warroom. """ raw_response = client.list_item_allow_block_list( access_control=args["access_control"], q=args.get("query"), sort_column=args.get("sort_column"), sort_order=args.get("sort_order", SortOrder.DESC.value), from_date=convert_to_epoch_timestamp(args.get("after")), to_date=convert_to_epoch_timestamp(args.get("before")), limit=arg_to_number(args.get("limit", DEFAULT_LIMIT), required=True), page=arg_to_number(args.get("page")), page_size=arg_to_number(args.get("page_size")), ) outputs = raw_response.get("items", []) title = "Allow" if args["access_control"] == AccessControl.WHITELIST else "Block" readable_output = tableToMarkdown( name=f"{title} List Item(s)", t=outputs, headerTransform=string_to_table_header, headers=[ "id", "type", "value", "description", "date_created", "date_amended", ], removeNull=True, ) return CommandResults( outputs_prefix=f"{INTEGRATION_PREFIX}.{title}", outputs_key_field="id", outputs=outputs, readable_output=readable_output, raw_response=raw_response, ) @logger def update_item_allow_block_list_command(client: QuarantineClient, args: dict[str, Any]) -> CommandResults: """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/block list. Args: client (QuarantineClient): A session to run HTTP requests to the API. args (dict[str, Any]): Arguments passed down by the CLI to configure the request. Returns: CommandResults: Outputs of the command that represent an entry in the warroom. """ client.action_item_allow_block_list( access_control=args["access_control"], suduls_user=args["suduls_user"], action=AccessControlAction.MERGE.value, email_or_domain=args["email_or_domain"], description=args["description"], suduls_item_id=args.get("item_id"), ) return CommandResults(readable_output="## The items were successfully merged.") @logger def delete_item_allow_block_list_command(client: QuarantineClient, args: dict[str, Any]) -> CommandResults: """Allows a SUDULS (allow quarantine users to maintain their own lists of email addresses or domains) user to delete an item from the allow/block list. Args: client (QuarantineClient): A session to run HTTP requests to the API. args (dict[str, Any]): Arguments passed down by the CLI to configure the request. Returns: CommandResults: Outputs of the command that represent an entry in the warroom. """ client.action_item_allow_block_list( access_control=args["access_control"], action=AccessControlAction.DELETE.value, suduls_item_id=args["item_id"], ) return CommandResults(readable_output="## The items were successfully deleted.") @logger def fetch_incidents( client: Client, last_run: dict[str, Any], first_fetch_time: datetime, max_results: int = MAX_INCIDENTS_TO_FETCH, accepted_severities: list | None = None, feed_type: str = "all", include_delivery: bool = False, ) -> tuple[dict[str, Any], list[dict[str, Any]]]: """This function will execute each interval (default is 1 minute). Args: client (Client): A session to run HTTP requests to the API. last_run (dict[str, Any]): The greatest incident created_time we fetched from last fetch. first_fetch_time (datetime): If last_run is None then fetch all incidents since first_fetch_time. max_results (int, optional): Maximum numbers of incidents per fetch. Defaults to MAX_INCIDENTS_TO_FETCH. feed_type (str, optional): The name of the data feed to retrieve. 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. - ec-reports: contextual information about emails blocked by Anti-Malware service. Defaults to "all". include_delivery (bool, optional): 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. Defaults to False Returns: tuple[dict[str, Any], list[dict[str, Any]]]: - next_run: This will be last_run in the next fetch-incidents. - incidents: Incidents that will be created in Cortex XSOAR. """ if last_fetch := last_run.get("last_fetch"): reset = last_fetch else: reset = first_fetch_time last_ids: list[str] = last_run.get("last_ids", []) incidents: list[dict[str, Any]] = [] demisto.debug(f"New run {last_fetch=}, {last_ids=}.") # Reset data feed timer to given start time. client.list_data( feed_type=feed_type, reset=convert_datetime_string(reset), ) # Fetch email data feed from start time. raw_response = cast( list[dict[str, Any]], client.list_data( feed_type=feed_type, include="delivery" if feed_type == "all" and include_delivery else None, ), ) seen_ids = [] items = raw_response or [] demisto.debug(f"Received {len(items)} feed items from the server.") for item in items: if not (email_info := item.get("emailInfo")) or not (item_incidents := item.get("incidents")): continue incident_id = email_info.get("xMsgRef") seen_ids.append(incident_id) # Skip incident if occurred time is less than last fetch if incident_id in last_ids: continue worst_incident = max( item_incidents, key=lambda incident: SEVERITY_MAPPING.get(incident.get("severity"), IncidentSeverity.UNKNOWN), ) severity = SEVERITY_MAPPING[worst_incident["severity"]] if accepted_severities and severity not in accepted_severities: continue last_fetch = str(email_info["mailProcessingStartTime"]) demisto.debug(f"Found new incident: {incident_id}.") item["incident_type"] = "email_data_feed" incidents.append( { "name": f"{get_integration_name()} - Email Data Feeds - {worst_incident['verdict']} - {incident_id}", "occurred": timestamp_to_datestring(last_fetch), "severity": severity, "details": worst_incident["reason"], "rawJSON": json.dumps(item), } ) if len(incidents) == max_results: break demisto.debug(f"Fetched {len(incidents)} incidents, setting next run to {last_fetch}.") next_run = {"email_data_feeds": {"last_fetch": last_fetch, "last_ids": seen_ids}} return next_run, incidents @logger def fetch_incidents_quarantine( client: QuarantineClient, last_run: dict[str, Any], first_fetch_time: datetime, max_results: int = MAX_INCIDENTS_TO_FETCH, query: str | None = None, filter_type: QuarantineType | None = None, admin_domain: str | None = None, ) -> tuple[dict[str, Any], list[dict[str, Any]]]: """This function will execute each interval (default is 1 minute). Args: client (Client): A session to run HTTP requests to the API. last_run (dict[str, Any]): The greatest incident created_time we fetched from last fetch. first_fetch_time (datetime): If last_run is None then fetch all incidents since first_fetch_time. max_results (int, optional): Maximum numbers of incidents per fetch. Defaults to MAX_INCIDENTS_TO_FETCH. query: (str | None, optional): A search criterion that can be used to filter emails that match only certain conditions based on email metadata. Defaults to None. filter_type: (QuarantineType | None, optional): A string used to filter emails based on the quarantine type. COMPLIANCE: Includes Content control, DLP and Image control emails. DLP: Includes only DLP emails. Defaults to None. admin_domain: (str | None, optional): 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. Defaults to None. Returns: tuple[dict[str, Any], list[dict[str, Any]]]: - next_run: This will be last_run in the next fetch-incidents. - incidents: Incidents that will be created in Cortex XSOAR. """ if last_fetch := last_run.get("last_fetch"): after = last_fetch else: after = convert_to_epoch_timestamp(first_fetch_time) last_ids: list[str] = last_run.get("last_ids", []) incidents: list[dict[str, Any]] = [] demisto.debug(f"New run {last_fetch=}, {last_ids=}.") response = client.list_quarantine_email( q=query, sort_order=SortOrder.ASC.value, after=after, filter_type=filter_type, admin_domain=admin_domain, limit=max_results, ) seen_ids = [] items = response.get("mail_list", []) demisto.debug(f"Received {len(items)} quarantined emails from the server.") for item in items: incident_id = item.get("id") seen_ids.append(incident_id) # Skip incident if occurred time is less than last fetch if incident_id in last_ids: continue response = client.preview_quarantine_email(incident_id) item |= response.get("details", {}) metadata = item.get("metadata", {}) last_fetch = str(metadata.get("email_date_received")) demisto.debug(f"Found new incident: {incident_id}.") item["incident_type"] = "email_quarantine" incidents.append( { "name": ( f"{get_integration_name()}" " - Email Quarantine" f" - {dict_safe_get(metadata, ['quarantine_info', 'quarantine_type'])}" f" - {incident_id}" ), "occurred": timestamp_to_datestring(last_fetch), "severity": IncidentSeverity.UNKNOWN, "details": f"Reason: {metadata.get('quarantine_reason')}", "rawJSON": json.dumps(item), } ) if len(incidents) == max_results: break demisto.debug(f"Fetched {len(incidents)} incidents, setting next run to {last_fetch}.") next_run = {"email_quarantine": {"last_fetch": last_fetch, "last_ids": seen_ids}} return next_run, incidents """ Entry Point """ def main() -> None: params = demisto.params() args = demisto.args() command = demisto.command() url_ioc: str | None = params.get("url_ioc") url_data_feeds: str | None = params.get("url_data_feeds") url_email_queue: str | None = params.get("url_email_queue") url_quarantine: str | None = params.get("url_quarantine") username: str = dict_safe_get(params, ["credentials", "identifier"]) password: str = dict_safe_get(params, ["credentials", "password"]) quarantine_username: str = dict_safe_get(params, ["quarantine_credentials", "identifier"]) quarantine_password: str = dict_safe_get(params, ["quarantine_credentials", "password"]) verify_certificate: bool = not argToBoolean(params.get("insecure", False)) proxy: bool = argToBoolean(params.get("proxy", False)) credentials_commands = { f"{COMMAND_PREFIX}-ioc-list": list_ioc_command, f"{COMMAND_PREFIX}-ioc-action": action_ioc_command, f"{COMMAND_PREFIX}-ioc-renew": renew_ioc_command, f"{COMMAND_PREFIX}-data-list": list_data_command, f"{COMMAND_PREFIX}-email-queue-list": list_email_queue_command, } quarantine_commands = { f"{COMMAND_PREFIX}-quarantine-email-list": list_quarantine_email_command, f"{COMMAND_PREFIX}-quarantine-email-preview": preview_quarantine_email_command, f"{COMMAND_PREFIX}-quarantine-email-release": release_quarantine_email_command, f"{COMMAND_PREFIX}-quarantine-email-delete": delete_quarantine_email_command, f"{COMMAND_PREFIX}-item-allow-list": list_item_allow_block_command, f"{COMMAND_PREFIX}-item-allow-list-update": update_item_allow_block_list_command, f"{COMMAND_PREFIX}-item-allow-list-delete": delete_item_allow_block_list_command, f"{COMMAND_PREFIX}-item-block-list": list_item_allow_block_command, f"{COMMAND_PREFIX}-item-block-list-update": update_item_allow_block_list_command, f"{COMMAND_PREFIX}-item-block-list-delete": delete_item_allow_block_list_command, } command_to_url = { "fetch-incidents": url_data_feeds, f"{COMMAND_PREFIX}-ioc-list": url_ioc, f"{COMMAND_PREFIX}-ioc-action": url_ioc, f"{COMMAND_PREFIX}-ioc-renew": url_ioc, f"{COMMAND_PREFIX}-data-list": url_data_feeds, f"{COMMAND_PREFIX}-email-queue-list": url_email_queue, } demisto.debug(f"Command being called is {command}") if "item-allow-list" in command: args["access_control"] = AccessControl.WHITELIST.value elif "item-block-list" in command: args["access_control"] = AccessControl.BLACKLIST.value try: client, quarantine_client = determine_clients( command=command, username=username, password=password, command_to_url=command_to_url, has_any_client_url=any((url_ioc, url_data_feeds, url_email_queue)), quarantine_username=quarantine_username, quarantine_password=quarantine_password, url_quarantine=url_quarantine, verify_certificate=verify_certificate, proxy=proxy, ) is_fetch = command == "fetch-incidents" if command == "test-module": return_results( test_module( credentials=(username, password) if username and password else None, url_ioc=url_ioc, url_data_feeds=url_data_feeds, url_email_queue=url_email_queue, quarantine_client=quarantine_client, verify=verify_certificate, proxy=proxy, ) ) elif is_fetch: fetch_type = params.get("fetch_type", "both") if any( ( fetch_type == "email_data_feed" and not client, fetch_type == "email_quarantine" and not quarantine_client, fetch_type == "both" and not (client and quarantine_client), ) ): raise DemistoException("Credentials for the selected fetch type are missing.") first_fetch_time = arg_to_datetime( arg=params["first_fetch"], arg_name="First fetch time", required=True, ) max_results = min( arg_to_number( arg=params.get("max_fetch"), arg_name="max_fetch", required=False, ) or MAX_INCIDENTS_TO_FETCH, MAX_INCIDENTS_TO_FETCH, ) last_run = demisto.getLastRun() both_next_run: dict[str, Any] = {} both_incidents: list[dict[str, Any]] = [] if fetch_type in ["both", "email_data_feed"]: accepted_severities = [ getattr(IncidentSeverity, severity.upper()) for severity in argToList(params.get("severity")) ] feed_type = params.get("type", "all") include_delivery = argToBoolean(params.get("include_delivery", False)) next_run, incidents = fetch_incidents( client=client, last_run=last_run.get("email_data_feed", {}), first_fetch_time=first_fetch_time, max_results=max_results, accepted_severities=accepted_severities, feed_type=feed_type, include_delivery=include_delivery, ) both_next_run |= next_run both_incidents += incidents if fetch_type in ["both", "email_quarantine"]: next_run, incidents = fetch_incidents_quarantine( client=quarantine_client, last_run=last_run.get("email_quarantine", {}), first_fetch_time=first_fetch_time, max_results=max_results, query=params.get("query_quarantine"), filter_type=params.get("type_quarantine"), admin_domain=params.get("admin_domain_quarantine"), ) both_next_run |= next_run both_incidents += incidents demisto.setLastRun(both_next_run) demisto.incidents(both_incidents) elif command in credentials_commands: if not client: raise DemistoException( f"To execute the {command} command, please ensure that 'Credentials' are provided and valid." ) return_results(credentials_commands[command](client, args)) elif command in quarantine_commands: if not quarantine_client: raise DemistoException( f"To execute the {command} command, please ensure 'Quarantine Credentials' are provided and valid." ) return_results(quarantine_commands[command](quarantine_client, args)) else: raise NotImplementedError(f"{command} command is not implemented.") except Exception as e: return_error(str(e)) if __name__ in ["__main__", "builtin", "builtins"]: main()