SendEmailToManager

Send an approval email to the manager of the employee with the given email allowing the manager to reply directly into the incident.

python · Active Directory Query

Source

import textwrap
from string import Template

import demistomock as demisto  # noqa: F401
from CommonServerPython import *  # noqa: F401

from CommonServerUserPython import *


def find_additional_incident_info(incident: dict) -> dict:
    additional_info = {}

    if incident.get("labels"):
        for label in incident["labels"]:
            if label["type"] == "Email/from":
                additional_info["employee_email"] = label["value"].lower()

        if incident.get("name"):
            additional_info["incident_subject"] = incident["name"]

        if incident.get("details"):
            additional_info["employee_request"] = incident["details"]

    return additional_info


def find_additional_ad_info(email: str, manager_attribute: str) -> dict:
    additional_info = {}

    filter_str = rf"(&(objectClass=user)(mail={email}))"
    response = demisto.executeCommand("ad-search", {"filter": filter_str, "attributes": "displayName," + manager_attribute})

    if response and isError(response[0]):
        demisto.results(response)
        sys.exit(0)

    if not (type(response) is list and type(response[0].get("Contents")) is list and type(response[0]["Contents"][0]) is dict):
        demisto.results("Unable to find manager email.")
        sys.exit(0)

    data = response[0]["Contents"][0]

    if data.get("manager_attribute") and type(data["manager_attribute"]) is list:
        additional_info["manager_dn"] = data[manager_attribute][0]

    # This was added as the json structure returned from the AD search during testing
    # seems to be different from the original.
    elif (
        data.get("attributes")
        and data["attributes"].get(manager_attribute)
        and type(data["attributes"][manager_attribute]) is list
    ):
        additional_info["manager_dn"] = data["attributes"][manager_attribute][0]

    else:
        demisto.results("Unable to find manager email.")
        sys.exit(0)

    if data.get("displayName") and type(data["displayName"]) is list:
        additional_info["employee_name"] = data["displayName"][0]

    # This was added as the json structure returned from the AD search during testing
    # seems to be different from the original.
    elif data.get("attributes") and data["attributes"].get("displayName") and type(data["attributes"]["displayName"]) is list:
        additional_info["employee_name"] = data["attributes"]["displayName"][0]

    filter_str = rf'(&(objectClass=User)(distinguishedName={additional_info["manager_dn"]}))'
    response = demisto.executeCommand("ad-search", {"filter": filter_str, "attributes": "displayName,mail"})

    if response and isError(response[0]):
        demisto.results(response)
        sys.exit(0)

    if type(response) is list and type(response[0].get("Contents")) is list and type(response[0]["Contents"][0]) is dict:
        data = response[0]["Contents"][0]

        if data.get("mail") and type(data["mail"]) is list:
            additional_info["manager_email"] = data["mail"][0]

        # This was added as the json structure returned from the AD search during testing
        # seems to be different from the original.
        elif data.get("attributes") and data["attributes"].get("mail") and type(data["attributes"]["mail"]) is list:
            additional_info["manager_email"] = data["attributes"]["mail"][0]

        if data.get("displayName") and type(data["displayName"]) is list:
            additional_info["manager_name"] = data["displayName"][0]

        # This was added as the json structure returned from the AD search during testing
        # seems to be different from the original.
        elif data.get("attributes") and data["attributes"].get("displayName") and type(data["attributes"]["displayName"]) is list:
            additional_info["manager_name"] = data["attributes"]["displayName"][0]

    return additional_info


def generate_mail_subject(
    incident_subject: str,
    investigation_id: str,
    allow_reply: bool,
    persistent: Optional[bool] = None,
    reply_entries_tag: Optional[str] = None,
) -> str:
    subject = incident_subject + f" - #{investigation_id}"

    if allow_reply:
        params = {}

        if persistent is not None:
            persistent_str = str(persistent).lower()
            params["persistent"] = persistent_str

        if reply_entries_tag is not None:
            params["replyEntriesTag"] = reply_entries_tag

        response = demisto.executeCommand("addEntitlement", params)

        if response and isError(response[0]):
            demisto.results(response)
            sys.exit(0)

        entitlement = demisto.get(response[0], "Contents")

        if not entitlement:
            demisto.results("Unable to get entitlement")
            sys.exit(0)

        subject += " " + entitlement

    return subject


def generate_mail_body(manager_name: str, employee_name: str, employee_request: str) -> str:
    body = """
    Hi $manager_name,
    We've received the following request below from $employee_name. \
    Please reply to this email with either "approve" or "deny".
    Cheers,
    Your friendly security team
    """

    body_template = Template(body)
    result_body = body_template.safe_substitute(manager_name=manager_name, employee_name=employee_name)
    result_body = textwrap.dedent(result_body)
    return result_body + "\n----------" + employee_request


def main():  # pragma: no cover
    args = demisto.args()
    email = args.get("email")
    manager_attribute = args.get("manager", "manager")
    allow_reply = argToBoolean(args.get("allowReply"))
    mail_body = args.get("body")
    employee_request = args.get("request")
    reply_entries_tag = args.get("replyEntriesTag")
    persistent = argToBoolean(args.get("persistent"))

    last_incident = demisto.incidents()[0]

    additional_info = find_additional_incident_info(last_incident)

    if not email:
        if additional_info.get("employee_email"):
            email = additional_info.get("employee_email")

        else:
            demisto.results("Could not find employee email.")

    additional_info.update(find_additional_ad_info(email=email, manager_attribute=manager_attribute))

    if not employee_request:
        employee_request = additional_info.get("employee_request")

    if not mail_body:
        mail_body = generate_mail_body(
            manager_name=additional_info["manager_name"],
            employee_name=additional_info["employee_name"],
            employee_request=employee_request,
        )

    demisto.results(
        demisto.executeCommand(
            "send-mail",
            {
                "to": additional_info["manager_email"],
                "subject": generate_mail_subject(
                    incident_subject=additional_info["incident_subject"],
                    investigation_id=demisto.investigation().get("id"),
                    allow_reply=allow_reply,
                    persistent=persistent,
                    reply_entries_tag=reply_entries_tag,
                ),
                "body": mail_body,
            },
        )
    )


if __name__ in ("__builtin__", "builtins", "__main__"):
    main()

README

Send an approval email to the manager of the employee, allowing the manager to reply directly into the incident

Script Data


Name Description
Script Type python3
Tags communication
Cortex XSOAR Version 5.0.0

Dependencies


This script uses the following commands and scripts.

  • send-mail
  • ad-search

Inputs


Argument Name Description
email The employee email. We will send an email to his manager. If not provided will be taken from incident label ‘Email/from’
manager The manager attribute in Active Directory. Default is ‘manager’.
allowReply If true, we will add an entitlement to the subject allowing manager to reply to war room
body The contents of the email body. It’s a template that can include $empName and $managerName which will be replaced with actual values.
request The contents of the request from the manager. Will be added below the body. If none is provided, incident details will be taken.
replyEntriesTag Tag to add on email reply entries
persistent Indicates whether to use one-time entitlement or a persistent one

Outputs


There are no outputs for this script.