Microsoft Exchange¶
Table of Contents¶
Release Notes¶
Version |
Date |
Notes |
---|---|---|
v2.0.0 |
February |
UI update, Playbook Migration, Custom Layout, Data-tables, Timezone support and bug fixes |
v1.0.4 |
September 2022 |
Bugfix on Selftest |
v1.0.3 |
June 2022 |
Add support for Python 3.9. |
v1.0.2 |
June 2021 |
Fix for |
v1.0.1 |
December 2020 |
Added App Host support, Added proxy support. |
v1.0.0 |
August 2018 |
Initial Release. |
Overview¶
Integrate with Microsoft Exchange email and meeting functionality
This application extends the capabilities of the SOAR platform with Microsoft Exchange On-prem services and functionality. Emails from an exchange mailbox can now be read, written, sent, queried, deleted, and moved from within the platform. Both Online and in-person meetings can be scheduled and invites can be sent using this application. All extracted information is now tabulated and neatly displayed in a separate incident tab.
Key Features¶
Compose and send emails to multiple recipients.
Schedule an Online meeting in Microsoft Exchange and send out invites with links to the meeting.
Schedule an Offline meeting and send out invites with information regarding meeting venue.
Saved all scheduled meetings as incident notes or in a separate incident tab called Exchange.
Get emails from a user’s mailbox and filter them based on fundamental attributes including the sender’s email address, the location of the email’s folder, the subject, the body, and if it contains attachments.
Conduct a thorough search of the user’s mailbox by tunneling subfolders, conducting the search based on the beginning and ending dates of emails received, sorting emails by recency, and limiting the number of emails obtained.
Save all retrieved information as either artifacts or tabulate in a separate incident tab called Exchange.
Delete email permanently from a user’s mailbox or move them to the Trash folder.
Migrate all the contents of a folder to another.
Get mailbox information for a particular sender.
All the above mentioned functionality has now been incorporated with Playbooks
Requirements¶
This app supports the IBM Security QRadar SOAR Platform and the IBM Security QRadar SOAR for IBM Cloud Pak for Security.
SOAR platform¶
The SOAR platform supports two app deployment mechanisms, Edge Gateway (formerly App Host) and integration server.
If deploying to a SOAR platform with an integration server, the requirements are:
SOAR platform >=
46.0
.The app is in the older integration format (available from the AppExchange as a
zip
file which contains atar.gz
file).Integration server is running
resilient_circuits>=48.0.0
.If using an API key account, make sure the account provides the following minimum permissions:
Name
Permissions
Org Data
Read
Function
Read
The following SOAR platform guides provide additional information:
Edge Gateway Deployment Guide or App Host Deployment Guide: provides installation, configuration, and troubleshooting information, including proxy server settings.
Integration Server Guide: provides installation, configuration, and troubleshooting information, including proxy server settings.
System Administrator Guide: provides the procedure to install, configure and deploy apps.
The above guides are available on the IBM Documentation website at ibm.biz/soar-docs. On this web page, select your SOAR platform version. On the follow-on page, you can find the Edge Gateway Deployment Guide, App Host Deployment Guide, or Integration Server Guide by expanding Apps in the Table of Contents pane. The System Administrator Guide is available by expanding System Administrator.
Cloud Pak for Security¶
If you are deploying to IBM Cloud Pak for Security, the requirements are:
IBM Cloud Pak for Security >=
1.10
.Cloud Pak is configured with an Edge Gateway.
The app is in a container-based format (available from the AppExchange as a
zip
file).
The following Cloud Pak guides provide additional information:
Edge Gateway Deployment Guide or App Host Deployment Guide: provides installation, configuration, and troubleshooting information, including proxy server settings. From the Table of Contents, select Case Management and Orchestration & Automation > Orchestration and Automation Apps.
System Administrator Guide: provides information to install, configure, and deploy apps. From the IBM Cloud Pak for Security IBM Documentation table of contents, select Case Management and Orchestration & Automation > System administrator.
These guides are available on the IBM Documentation website at ibm.biz/cp4s-docs. From this web page, select your IBM Cloud Pak for Security version. From the version-specific IBM Documentation page, select Case Management and Orchestration & Automation.
Proxy Server¶
The app does support a proxy server.
Python Environment¶
Python 3.6 and Python 3.9 are supported. Additional package dependencies may exist for each of these packages:
exchangelib ~= 4.6.2;python_version==’3.6’
exchangelib ~= 4.9.0;python_version>=’3.9’
resilient_circuits>=48.0.0
Development Version¶
This app has been implemented using:
Product Name |
Product Version |
---|---|
Microsoft Exchange |
2016 |
Endpoint Developed With¶
This app has been implemented using Microsoft Exchange Server
Configuration¶
Please pay attention to the below mentioned pointers as the application can be slightly complex and confusing to configure.
Timezones¶
The application now has the ability to set a default timezone from the app.conf. Timezones are to be specified using their
Tz Database name
. Here are a few examples:
timezone = Europe/Dublin
timezone = Etc/GMT+2
timezone = Asia/Kolkata
timezone = Etc/GMT
Folder Paths¶
When the
Source location
or theexchange_folder_path
fields are left empty, they are substituted with the value specified fordefault_folder_path
in app.confThe path related fields might be slightly complicated to configure as they tend to vary with the Exchange environment. Upon entering an invalid folder path, a tree structure of the folder hierarchy will be printed. Here is an example:
Example folder paths given this folder structure could be any path following the root path:
Top of Information Store/Inbox
Top of Information Store/Deleted Items
Finder/Unread Mail
Finder
Additionally, if the
exchange_search_subfolders
path is set to true, every folder in its branch will be included in the query. For example if the specified folder is Recoverable Items, then the searched folders would be:Recoverable Items
Recoverable Items/Deletions
Recoverable Items/Purges
Recoverable Items/Versions
To search folder paths, the specified account in config file must have access to the searched folders. Folders that contain
/
or,
must be wrapped in quotes.Example/”One/With/Quotes”/Folder
Example/”One, with, commas”/Folder
Example/”One/with, both”/Folder
Multiple folder paths can be specified by separating them with commas and following the above rules.
Information as Data-tables or Artifacts¶
Information extracted from emails and meetings can now be either added as artifacts (legacy) or to data-tables present in the Exchange tab of an Incident. This behavior can be changed by toggling the
enable_write_to_datatables
option found in the Post processing scripts of the workflows.For more information on specific function inputs, check the tooltips.
Installation¶
Install¶
To install or uninstall an App or Integration on the SOAR platform, see the documentation at ibm.biz/soar-docs.
To install or uninstall an App on IBM Cloud Pak for Security, see the documentation at ibm.biz/cp4s-docs and follow the instructions above to navigate to Orchestration and Automation.
App Configuration¶
The following table provides the settings you need to configure the app. These settings are made in the app.config file. See the documentation discussed in the Requirements section for the procedure.
Config |
Required |
Example |
Description |
---|---|---|---|
default_folder_path |
Yes |
|
Some folder path after root Multiple folder paths must be separated by commas. |
server |
Yes |
|
Exchange server DNS name or ip address. |
Yes |
|
default account to send emails and create meetings if one was not specified. Specifying an account that is not this one will require impersonation access. |
|
username |
Yes |
|
Admin account with mailbox access to other accounts. |
password |
Yes |
|
Password of Admin account. |
verify_cert |
Yes |
|
Use a CA cert for access to an Exchange server. |
timezone |
No |
|
Default Timezone for the application. Used for Meetings and querying emails. |
Custom Layouts¶
Import the Data Tables and Custom Fields like the screenshot below:
Function - Exchange Create Meeting¶
Creates a meeting and sends out invitation to attendees. The user is provided with the option to choose required and optional attendees. If its a virtual meeting, the user now has the ability to specify the URL to the meeting room and mark the invite as an online meeting.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
Yes |
|
Email account that is used |
|
|
No |
|
Subject of exchange meeting |
|
|
No |
|
Body of exchange meeting |
|
|
Yes |
|
When the meeting should end |
|
|
Yes |
|
When the meeting should start |
|
|
No |
|
Comma separated list of optional attendees |
|
|
No |
|
Comma separated list of required attendees |
|
|
No |
|
If the meeting is conducted online, then the URL to the Room. Or the name of the physical location of the Meeting Room |
|
|
No |
|
Specifies if the location provided in the above filled is a link or not |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"body": "Please be present",
"content": {
"body": "Please be present",
"end_time": "2023-03-24 13:00:37",
"location": "https://example.com",
"online_meeting": true,
"optional_attendees": [
"johndoe.s.1@exchange2016.com"
],
"required_attendees": [
"sampleuser@exchange2016.com"
],
"sender": "johndoe.n@exchange2016.com",
"start_time": "2023-03-24 12:00:37",
"subject": "Security Weekly Meeting",
"timezone": "Etc/GMT"
},
"end_time": "2023-03-24 13:00:37",
"inputs": {
"inputs": {
"exchange_email": "johndoe.n@exchange2016.com",
"exchange_is_online_meeting": true,
"exchange_meeting_body": "Please be present",
"exchange_meeting_end_time": 1679662837000,
"exchange_meeting_location": "https://example.com",
"exchange_meeting_start_time": 1679659237000,
"exchange_meeting_subject": "Security Weekly Meeting",
"exchange_optional_attendees": "johndoe.s.1@exchange2016.com",
"exchange_required_attendees": "sampleuser@exchange2016.com"
}
},
"location": "https://example.com",
"metrics": {
"execution_time_ms": 3233,
"host": "exchange2016",
"package": "fn-exchange",
"package_version": "1.1.0",
"timestamp": "2023-03-01 14:28:03",
"version": "1.0"
},
"online_meeting": true,
"optional_attendees": [
"johndoe.s.1@exchange2016.com"
],
"raw": "{\"required_attendees\": [\"sampleuser@exchange2016.com\"], \"optional_attendees\": [\"johndoe.s.1@exchange2016.com\"], \"sender\": \"johndoe.n@exchange2016.com\", \"subject\": \"Security Weekly Meeting\", \"body\": \"Please be present\", \"start_time\": \"2023-03-24 12:00:37\", \"end_time\": \"2023-03-24 13:00:37\", \"timezone\": \"Etc/GMT\", \"location\": \"https://example.com\", \"online_meeting\": true}",
"reason": null,
"required_attendees": [
"sampleuser@exchange2016.com"
],
"sender": "johndoe.n@exchange2016.com",
"start_time": "2023-03-24 12:00:37",
"subject": "Security Weekly Meeting",
"success": true,
"timezone": "Etc/GMT",
"version": "1.0"
}
Example Pre-Process Script:
inputs.exchange_email = getattr(playbook.inputs, "exchange_email", None)
inputs.exchange_meeting_start_time = getattr(playbook.inputs, "exchange_meeting_start_time", None)
inputs.exchange_meeting_end_time = getattr(playbook.inputs, "exchange_meeting_end_time", None)
inputs.exchange_meeting_subject = getattr(playbook.inputs, "exchange_meeting_subject", None)
inputs.exchange_required_attendees = getattr(playbook.inputs, "exchange_required_attendees", None)
inputs.exchange_optional_attendees = getattr(playbook.inputs, "exchange_optional_attendees", None)
inputs.exchange_meeting_location = getattr(playbook.inputs, "exchange_meeting_location", None)
inputs.exchange_is_online_meeting = getattr(playbook.inputs, "exchange_is_online_meeting", False)
if playbook.inputs.exchange_meeting_body and playbook.inputs.exchange_meeting_body.content:
inputs.exchange_meeting_body = playbook.inputs.exchange_meeting_body.content
Push Meeting Invite to DataTable Script:
'''
Results:
--------
'required_attendees':required1@example.com,required2@example.com
'optional_attendees': optional1@example.com,...
'sender': sender@example.com
'subject': meeting subject
'body': meeting body
'start_time': 1655938800000
'end_time': 1656025200000
'location': https://meeting.room.com/meet/johndoe
'''
enable_write_to_datatables = True
from datetime import datetime
content = playbook.functions.results.output_exchange_create_meeting.get("content")
success = playbook.functions.results.output_exchange_create_meeting.get("success")
fail_reason = playbook.functions.results.output_exchange_create_meeting.get("reason")
if not success:
text = u"Unable to create meeting"
if fail_reason:
text = u"{0}:\n\tFailure reason: {1}".format(text, fail_reason)
noteText = helper.createRichText(text)
incident.addNote(noteText)
else:
required_attendees = ",".join(content.get('required_attendees')) if content.get('required_attendees') else ""
optional_attendees = ",".join(content.get('optional_attendees')) if content.get('optional_attendees') else ""
if content.get("online_meeting") is True:
location = u"""<a href='{0}'>Meeting URL</a>""".format(content.get('location')) if content.get("location") else ""
else:
location = content.get('location') if content.get("location") else ""
if enable_write_to_datatables:
message_row = incident.addRow("exchange_dt_meeting_information")
message_row.exchange_dt_created_time = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
message_row.exchange_dt_meeting_subject = content.get('subject')
message_row.exchange_dt_start_time = content.get('start_time')
message_row.exchange_dt_end_time = content.get('end_time')
message_row.exchange_dt_mandatory_attendees = required_attendees
message_row.exchange_dt_optional_attendees = optional_attendees
message_row.exchange_dt_meeting_location = helper.createRichText(location)
else:
text = "<b>Meeting created from Exchange Create Meeting:</b><br />"
text += f"<br />Subject: {content.get('subject')}"
text += f"<br />Start time: {content.get('start_time')}"
text += f"<br />End time: {content.get('end_time')}"
text += f"<br />Timezone: {content.get('timezone')}"
text += f"<br />Required Attendees: {required_attendees}"
text += f"<br />Optional Attendees: {optional_attendees}"
text += f"<br />Body: {content.get('body')}"
text += f"<br />Location: {location}"
text += f"<br />Online Meeting: {content.get('online_meeting')}"
noteText = helper.createRichText(text)
incident.addNote(noteText)
Function - Exchange Delete Emails¶
Emails can be queried from a user’s mailbox and deleted. These emails can be filtered based on fundamental attributes including the sender’s email address, the location of the email’s folder, the subject, the body, and if it contains attachments. A thorough search can be performed on the user’s mailbox by tunneling subfolders, beginning and ending dates of emails received, sorting emails by recency, and limiting the number of emails obtained. Once these emails are selected, the user has an option to either permanently delete the emails or move them to the Trash folder. The email information retrieved form the mailbox is now stored in a data-table available under the Exchange incident tab. The ability to store information as artifacts is also retained. This can be turned on from within the Push Emails to DataTables
of this Playbook.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
Yes |
|
Email account that is used |
|
|
No |
|
Comma separated list of email ids |
|
|
No |
|
Get emails until after this date, leave empty to not set an end date |
|
|
No |
|
Get emails on or after this date, leave empty to not set a start date |
|
|
No |
|
Comma separated list of folder paths to query from |
|
|
Yes |
|
Yes for hard deletion. No for soft deletion (move to deleted folder) |
|
|
No |
|
True to include attachments, False to exclude attachments, leave empty to get all |
|
|
No |
|
Text for the message body of an email to query or to send, depending on the function. |
|
|
No |
|
Text for the subject of an email to query or send depending on the function. |
|
|
No |
|
Number of emails to be selected |
|
|
No |
|
Yes to get newest emails first, No to get oldest emails first, leave empty to ignore time sent |
|
|
No |
|
Yes to search subfolders, No or leave empty to not search subfolders |
|
|
No |
|
Only get emails from this sender, leave blank to ignore sender attribute |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": {},
"inputs": {
"inputs": {
"exchange_email": "exampleuser1@outlook2016.com",
"exchange_message_ids": null,
"exchange_end_date": null,
"exchange_folder_path": null,
"exchange_hard_delete": false,
"exchange_has_attachments": null,
"exchange_message_subject": "Security Weekly Meeting",
"exchange_num_emails": 2,
"exchange_order_by_recency": null,
"exchange_search_subfolders": null,
"exchange_sender": null,
"exchange_start_date": null
}
},
"metrics": {
"execution_time_ms": 1293,
"host": "exchange2016",
"package": "fn-exchange",
"package_version": "1.0.5",
"timestamp": "2023-02-28 20:21:08",
"version": "1.0"
},
"raw": "{}",
"reason": "The SMTP address has no mailbox associated with it.",
"success": false,
"version": "1.0"
}
Example Pre-Process Script:
# Set inputs
# For for information on input values, read tooltips
# For information on input values, read tooltips
inputs.exchange_hard_delete = getattr(playbook.inputs, "exchange_hard_delete", False)
if inputs.exchange_hard_delete:
inputs.exchange_email_operation = "DELETED"
else:
inputs.exchange_email_operation = "TRASHED"
inputs.exchange_email = getattr(playbook.inputs, "exchange_email", None)
inputs.exchange_email_ids = getattr(playbook.inputs, "exchange_email_ids", None)
inputs.exchange_sender = getattr(playbook.inputs, "exchange_sender", None)
inputs.exchange_message_subject = getattr(playbook.inputs, "exchange_message_subject", None)
inputs.exchange_start_date = getattr(playbook.inputs, "exchange_start_date", None)
inputs.exchange_end_date = getattr(playbook.inputs, "exchange_end_date", None)
inputs.exchange_num_emails = getattr(playbook.inputs, "exchange_num_emails", None)
inputs.exchange_folder_path = getattr(playbook.inputs, "exchange_folder_path", None)
inputs.exchange_order_by_recency = getattr(playbook.inputs, "exchange_order_by_recency", None)
inputs.exchange_search_subfolders = getattr(playbook.inputs, "exchange_search_subfolders", None)
inputs.exchange_has_attachments = getattr(playbook.inputs, "exchange_has_attachments", None)
if playbook.inputs.exchange_message_body and playbook.inputs.exchange_message_body.content:
inputs.exchange_message_body = playbook.inputs.exchange_message_body.content
Push Emails to DataTables Script:
'''
Example function results:
------------------------
{
'email_ids': ['id1', 'idN'],
'emails': {
'id1': {
'subject': 'Email Subject',
'body': 'Subject body in HTML',
'mime_content': mime content of message
'sender_name': 'FirstName LastName',
'sender_email': 'example@example.com',
'attachment_ids': ['attachment_id1', 'attachment_id2'],
'attachments': {
'attachment_id1': {
'attachment_name': 'attachment.xslx',
'attachment_content_type': 'spreadsheet',
'attachment_size': '8842',
'attachment_base64': 'attachment encoded in base 64'},
'attachment_id2': {
'attachment_name': '...',
'attachment_content_type': '...',
'attachment_size': '...',
'attachment_base64': 'attachment encoded in base 64'}}},
'''
# Enable to add all information to a datatable found in the Exchange tab.
enable_write_to_datatables = True
# Enable to add attachments found as a base64 encoded value. This option only works when enable_write_to_datatables is set to False
enable_add_attachment_value = False
results = playbook.functions.results.output_exchange_emails
from datetime import datetime
fail_reason = results.get("reason")
content = results.get("content")
emails = content.get("emails")
email_ids = content.get("email_ids")
status_colour_map = {
"QUERIED" : "#B0C4DE", # LightSteelBlue
"MOVED" : "#B8860B", # DarkGoldenrod
"TRASHED" : "#CD5C5C", # IndianRed
"DELETED" : "#B22222"} # Firebrick
if not results.get("success"):
text = u"Unable to find emails"
if fail_reason:
text = u"{0}:\n\tFailure reason: {1}".format(text, fail_reason)
noteText = helper.createRichText(text)
incident.addNote(noteText)
else:
for email_id in email_ids:
email = emails.get(email_id)
attachment_ids = email.get('attachment_ids')
if enable_write_to_datatables:
email_status = results.get("inputs").get("inputs").get("exchange_email_operation")
email_status = u"""<p style= "color:{color}">{status} </p>""".format(color=status_colour_map[email_status], status=email_status)
message_row = incident.addRow("exchange_email_information_dt")
message_row.exchange_date_of_retrieval = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
message_row.exchange_dt_message_id = email_id
message_row.exchange_dt_recipient_email = email.get("sender_email", "-")
message_row.exchange_dt_sender_email = playbook.inputs.exchange_email
message_row.exchange_dt_email_status = helper.createRichText(email_status)
message_row.exchange_dt_message_subject = email.get("subject", "-")
message_row.exchange_dt_count_attachments = len(attachment_ids)
else:
attachments = email.get('attachments')
if email.get("sender_name"):
incident.addArtifact('Email Sender Name', email['sender_name'], 'Sender name for email {}'.format(email_id))
if email.get("sender_email"):
incident.addArtifact('Email Sender', email['sender_email'], 'Sender email address for email {}'.format(email_id))
if email.get("subject"):
incident.addArtifact('Email Subject', email['subject'], 'Email subject for email {}'.format(email_id))
if email.get("body"):
incident.addArtifact('Email Body', email['body'], 'Email body in HTML for email {}'.format(email_id))
for attachment_id in attachment_ids:
attachment = attachments.get(attachment_id)
incident.addArtifact('Email Attachment Name', attachment['attachment_name'], 'Attachment name for attachment {} from email {}'.format(attachment_id, email_id))
if enable_add_attachment_value:
incident.addArtifact('Email Attachment', attachment['attachment_base64'], 'Attachment file {} base64 encoded : {}'.format(attachment['attachment_name'], attachment['attachment_base64']))
Function - Exchange Find Emails¶
Emails can be queried from a user’s mailbox and deleted. These emails can be filtered based on fundamental attributes including the sender’s email address, the location of the email’s folder, the subject, the body, and if it contains attachments. A thorough search can be performed on the user’s mailbox by tunneling subfolders, beginning and ending dates of emails received, sorting emails by recency, and limiting the number of emails obtained. The email retrieved form the mailbox can now be stored in a data-table available under the Exchange incident tab. The ability to store information as artifacts is also retained. This can be turned on from within the Push Emails to DataTables Script
of this playbook.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
Yes |
|
Email account that is used |
|
|
No |
|
Comma separated list of email ids |
|
|
No |
|
Get emails on or after this date, leave empty to not set a start date |
|
|
No |
|
Get emails until after this date, leave empty to not set an end date |
|
|
No |
|
Comma separated list of folder paths to query from |
|
|
No |
|
True to include attachments, False to exclude attachments, leave empty to get all |
|
|
No |
|
Text for the message body of an email to query or to send, depending on the function. |
|
|
No |
|
Text for the subject of an email to query or send depending on the function. |
|
|
No |
|
Number of emails to be selected |
|
|
No |
|
Yes to get newest emails first, No to get oldest emails first, leave empty to ignore time sent |
|
|
No |
|
Yes to search subfolders, No or leave empty to not search subfolders |
|
|
No |
|
Only get emails from this sender, leave blank to ignore sender attribute |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": {
"email_ids": [
"\u003c8a9cc4cff1414ae38fa9b3fa85674f04@exchange2016.com\u003e",
"\u003c53fe9fb07c4b48218c611b835c1e9603@exchange2016.com\u003e"
],
"emails": {
"\u003c53fe9fb07c4b48218c611b835c1e9603@exchange2016.com\u003e": {
"attachment_ids": [],
"attachments": {},
"body": "\u003chtml\u003e\r\n\u003chead\u003e\r\n\u003cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"\u003e\r\n\u003cstyle type=\"text/css\" style=\"display:none;\"\u003e\u003c!-- P {margin-top:0;margin-bottom:0;} --\u003e\u003c/style\u003e\r\n\u003c/head\u003e\r\n\u003cbody dir=\"ltr\"\u003e\r\n\u003cdiv id=\"divtagdefaultwrapper\" style=\"font-size:12pt;color:#000000;font-family:Calibri,Helvetica,sans-serif;\" dir=\"ltr\"\u003e\r\n\u003cp\u003esent from \u003cspan\u003ejohndoe.s.1@exchange2016.com\u003c/span\u003e\u003cbr\u003e\r\n\u003c/p\u003e\r\n\u003c/div\u003e\r\n\u003c/body\u003e\r\n\u003c/html\u003e\r\n",
"sender_email": "johndoe@exchange2016.com",
"sender_name": "John Doe",
"subject": "test shared mailbox"
},
"\u003c8a9cc4cff1414ae38fa9b3fa85674f04@exchange2016.com\u003e": {
"attachment_ids": [],
"attachments": {},
"body": "\u003chtml\u003e\r\n\u003chead\u003e\r\n\u003cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"\u003e\r\n\u003cstyle type=\"text/css\" style=\"display:none;\"\u003e\u003c!-- P {margin-top:0;margin-bottom:0;} --\u003e\u003c/style\u003e\r\n\u003c/head\u003e\r\n\u003cbody dir=\"ltr\"\u003e\r\n\u003cdiv id=\"divtagdefaultwrapper\" style=\"font-size:12pt;color:#000000;font-family:Calibri,Helvetica,sans-serif;\" dir=\"ltr\"\u003e\r\n\u003cp\u003e\u003cspan\u003esend to shared mailbox\u003c/span\u003e\u003cbr\u003e\r\n\u003c/p\u003e\r\n\u003c/div\u003e\r\n\u003c/body\u003e\r\n\u003c/html\u003e\r\n",
"sender_email": "johndoe@exchange2016.com",
"sender_name": "John Doe",
"subject": "send to shared mailbox"
}
}
},
"email_ids": [
"\u003c8a9cc4cff1414ae38fa9b3fa85674f04@exchange2016.com\u003e",
"\u003c53fe9fb07c4b48218c611b835c1e9603@exchange2016.com\u003e"
],
"emails": {
"\u003c53fe9fb07c4b48218c611b835c1e9603@exchange2016.com\u003e": {
"attachment_ids": [],
"attachments": {},
"body": "\u003chtml\u003e\r\n\u003chead\u003e\r\n\u003cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"\u003e\r\n\u003cstyle type=\"text/css\" style=\"display:none;\"\u003e\u003c!-- P {margin-top:0;margin-bottom:0;} --\u003e\u003c/style\u003e\r\n\u003c/head\u003e\r\n\u003cbody dir=\"ltr\"\u003e\r\n\u003cdiv id=\"divtagdefaultwrapper\" style=\"font-size:12pt;color:#000000;font-family:Calibri,Helvetica,sans-serif;\" dir=\"ltr\"\u003e\r\n\u003cp\u003esent from \u003cspan\u003ejohndoe.s.1@exchange2016.com\u003c/span\u003e\u003cbr\u003e\r\n\u003c/p\u003e\r\n\u003c/div\u003e\r\n\u003c/body\u003e\r\n\u003c/html\u003e\r\n",
"sender_email": "johndoe@exchange2016.com",
"sender_name": "John Doe",
"subject": "test shared mailbox"
},
"\u003c8a9cc4cff1414ae38fa9b3fa85674f04@exchange2016.com\u003e": {
"attachment_ids": [],
"attachments": {},
"body": "\u003chtml\u003e\r\n\u003chead\u003e\r\n\u003cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"\u003e\r\n\u003cstyle type=\"text/css\" style=\"display:none;\"\u003e\u003c!-- P {margin-top:0;margin-bottom:0;} --\u003e\u003c/style\u003e\r\n\u003c/head\u003e\r\n\u003cbody dir=\"ltr\"\u003e\r\n\u003cdiv id=\"divtagdefaultwrapper\" style=\"font-size:12pt;color:#000000;font-family:Calibri,Helvetica,sans-serif;\" dir=\"ltr\"\u003e\r\n\u003cp\u003e\u003cspan\u003esend to shared mailbox\u003c/span\u003e\u003cbr\u003e\r\n\u003c/p\u003e\r\n\u003c/div\u003e\r\n\u003c/body\u003e\r\n\u003c/html\u003e\r\n",
"sender_email": "johndoe@exchange2016.com",
"sender_name": "John Doe",
"subject": "send to shared mailbox"
}
},
"inputs": {
"inputs": {
"exchange_email": "johndoe.s.1@exchange2016.com",
"exchange_message_ids": null,
"exchange_end_date": null,
"exchange_folder_path": null,
"exchange_has_attachments": null,
"exchange_message_subject": null,
"exchange_num_emails": 2,
"exchange_order_by_recency": null,
"exchange_search_subfolders": null,
"exchange_sender": null,
"exchange_start_date": null
}
},
"metrics": {
"execution_time_ms": 190199,
"host": "exchange2016",
"package": "fn-exchange",
"package_version": "1.0.5",
"timestamp": "2023-02-28 15:51:03",
"version": "1.0"
},
"reason": null,
"success": true,
"version": "1.0"
}
Example Pre-Process Script:
# For information on input values, read tooltips
inputs.exchange_email_operation = "QUERIED"
inputs.exchange_email = getattr(playbook.inputs, "exchange_email", None)
inputs.exchange_email_ids = getattr(playbook.inputs, "exchange_email_ids", None)
inputs.exchange_sender = getattr(playbook.inputs, "exchange_sender", None)
inputs.exchange_message_subject = getattr(playbook.inputs, "exchange_message_subject", None)
inputs.exchange_start_date = getattr(playbook.inputs, "exchange_start_date", None)
inputs.exchange_end_date = getattr(playbook.inputs, "exchange_end_date", None)
inputs.exchange_num_emails = getattr(playbook.inputs, "exchange_num_emails", None)
inputs.exchange_folder_path = getattr(playbook.inputs, "exchange_folder_path", None)
inputs.exchange_order_by_recency = getattr(playbook.inputs, "exchange_order_by_recency", None)
inputs.exchange_search_subfolders = getattr(playbook.inputs, "exchange_search_subfolders", None)
inputs.exchange_has_attachments = getattr(playbook.inputs, "exchange_has_attachments", None)
if playbook.inputs.exchange_message_body and playbook.inputs.exchange_message_body.content:
inputs.exchange_message_body = playbook.inputs.exchange_message_body.content
Push Emails to DataTables Script:
'''
Example function results:
------------------------
{
'email_ids': ['id1', 'idN'],
'emails': {
'id1': {
'subject': 'Email Subject',
'body': 'Subject body in HTML',
'mime_content': mime content of message
'sender_name': 'FirstName LastName',
'sender_email': 'example@example.com',
'attachment_ids': ['attachment_id1', 'attachment_id2'],
'attachments': {
'attachment_id1': {
'attachment_name': 'attachment.xslx',
'attachment_content_type': 'spreadsheet',
'attachment_size': '8842',
'attachment_base64': 'attachment encoded in base 64'},
'attachment_id2': {
'attachment_name': '...',
'attachment_content_type': '...',
'attachment_size': '...',
'attachment_base64': 'attachment encoded in base 64'}}},
'''
# Enable to add all information to a datatable found in the Exchange tab.
enable_write_to_datatables = True
# Enable to add attachments found as a base64 encoded value. This option only works when enable_write_to_datatables is set to False
enable_add_attachment_value = False
results = playbook.functions.results.output_exchange_emails
from datetime import datetime
fail_reason = results.get("reason")
content = results.get("content")
emails = content.get("emails")
email_ids = content.get("email_ids")
status_colour_map = {
"QUERIED" : "#B0C4DE", # LightSteelBlue
"MOVED" : "#B8860B", # DarkGoldenrod
"TRASHED" : "#CD5C5C", # IndianRed
"DELETED" : "#B22222"} # Firebrick
if not results.get("success"):
text = u"Unable to find emails"
if fail_reason:
text = u"{0}:\n\tFailure reason: {1}".format(text, fail_reason)
noteText = helper.createRichText(text)
incident.addNote(noteText)
else:
for email_id in email_ids:
email = emails.get(email_id)
attachment_ids = email.get('attachment_ids')
if enable_write_to_datatables:
email_status = results.get("inputs").get("inputs").get("exchange_email_operation")
email_status = u"""<p style= "color:{color}">{status} </p>""".format(color=status_colour_map[email_status], status=email_status)
message_row = incident.addRow("exchange_email_information_dt")
message_row.exchange_date_of_retrieval = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
message_row.exchange_dt_message_id = email_id
message_row.exchange_dt_recipient_email = email.get("sender_email", "-")
message_row.exchange_dt_sender_email = playbook.inputs.exchange_email
message_row.exchange_dt_email_status = helper.createRichText(email_status)
message_row.exchange_dt_message_subject = email.get("subject", "-")
message_row.exchange_dt_count_attachments = len(attachment_ids)
else:
attachments = email.get('attachments')
if email.get("sender_name"):
incident.addArtifact('Email Sender Name', email['sender_name'], 'Sender name for email {}'.format(email_id))
if email.get("sender_email"):
incident.addArtifact('Email Sender', email['sender_email'], 'Sender email address for email {}'.format(email_id))
if email.get("subject"):
incident.addArtifact('Email Subject', email['subject'], 'Email subject for email {}'.format(email_id))
if email.get("body"):
incident.addArtifact('Email Body', email['body'], 'Email body in HTML for email {}'.format(email_id))
for attachment_id in attachment_ids:
attachment = attachments.get(attachment_id)
incident.addArtifact('Email Attachment Name', attachment['attachment_name'], 'Attachment name for attachment {} from email {}'.format(attachment_id, email_id))
if enable_add_attachment_value:
incident.addArtifact('Email Attachment', attachment['attachment_base64'], 'Attachment file {} base64 encoded : {}'.format(attachment['attachment_name'], attachment['attachment_base64']))
Function - Exchange Get Mailbox Info¶
Get mailbox info for specified email. The information retrieved from the server is saved as a incident note.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
Yes |
|
Email to get mailbox info from |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": {
"email_address": "johndoe.n@exchange2016.com",
"mailbox_type": "Mailbox",
"name": "John Doe",
"routing_type": "SMTP"
},
"email_address": "johndoe.n@exchange2016.com",
"inputs": {
"inputs": {
"exchange_get_email": "johndoe.n@exchange2016.com"
}
},
"mailbox_type": "Mailbox",
"metrics": {
"execution_time_ms": 254,
"host": "exchange2016",
"package": "fn-exchange",
"package_version": "1.1.0",
"timestamp": "2023-03-02 12:21:02",
"version": "1.0"
},
"name": "John Doe",
"raw": "{\"name\": \"John Doe\", \"email_address\": \"johndoe.n@exchange2016.com\", \"routing_type\": \"SMTP\", \"mailbox_type\": \"Mailbox\"}",
"reason": null,
"success": true,
"version": "1.0"
}
Example Pre-Process Script:
inputs.exchange_get_email = getattr(playbook.inputs, "exchange_get_email", None)
Example Post-Process Script:
'''
Example
-------
response = {
'name': 'firstname lastname',
'email_address': 'user@example.com',
'routing_type': 'SMTP',
'mailbox_type': 'Mailbox'}
'''
write_to_artifact = False
results = playbook.functions.results.output_exchange_get_mailbox
content = results.get("content")
if not results.get("success"):
text = u"Unable to create meeting"
fail_reason = results.get("reason")
if fail_reason:
text += u"Failure reason: {}".format(fail_reason)
else:
if write_to_artifact:
incident.addArtifact('Email Sender', content.get('email_address'), 'Email address from Exchange Get Mailbox Info')
incident.addArtifact('Email Sender Name', content.get('name'), 'Email sender name from Exchange Get Mailbox Info')
text = "<b>Microsoft Exchange Mailbox Information:</b><br />"
text += f"<br />Name: {content.get('name')}"
text += f"<br />Email Address: {content.get('email_address')}"
text += f"<br />Routing Type: {content.get('routing_type')}"
text += f"<br />Mailbox Type: {content.get('mailbox_type')}"
noteText = helper.createRichText(text)
incident.addNote(noteText)
Function - Exchange Move Emails¶
Move queried emails from a specified folder to another specified folder. The exchange_destination_folder_path
must be specified to perform this action. If the user decides to migrate all contents form one folder to another and delete the source, exchange_delete_source_folder
must be enabled. Emails can be queried from a user’s mailbox and deleted. These emails can be filtered based on fundamental attributes including the sender’s email address, the location of the email’s folder, the subject, the body, and if it contains attachments. A thorough search can be performed on the user’s mailbox by tunneling subfolders, beginning and ending dates of emails received, sorting emails by recency, and limiting the number of emails obtained. The email retrieved form the mailbox can now be stored in a data-table available under the Exchange incident tab. The ability to store information as artifacts is also retained. This can be turned on from within the Push Emails to DataTables
script of this playbook.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
Yes |
|
Move the emails to another folder and delete the current folder |
|
|
Yes |
|
Folder path of destination folder from root folder, leave empty for root folder |
|
|
Yes |
|
Email account that is used |
|
|
No |
|
Comma separated list of email ids |
|
|
No |
|
Get emails on or after this date, leave empty to not set a start date |
|
|
No |
|
Get emails until after this date, leave empty to not set an end date |
|
|
No |
|
Comma separated list of folder paths to query from |
|
|
Yes |
|
Yes to delete even if the folder has subfolders else stops operation |
|
|
No |
|
True to include attachments, False to exclude attachments, leave empty to get all |
|
|
No |
|
Text for the message body of an email to query or to send, depending on the function. |
|
|
No |
|
Text for the subject of an email to query or send depending on the function. |
|
|
No |
|
Number of emails to be selected |
|
|
No |
|
Yes to get newest emails first, No to get oldest emails first, leave empty to ignore time sent |
|
|
No |
|
Yes to search subfolders, No or leave empty to not search subfolders |
|
|
No |
|
Only get emails from this sender, leave blank to ignore sender attribute |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": {
"dst_folder": "Top of Information Store/Notes",
"email_ids": [
"\u003cdacfdd29axxxxxxxxxxxxxxxx4d9@exchange2016.com\u003e",
"\u003c3e563564exxxxxxxxxxxxxxxx570@exchange2016.com\u003e",
"\u003cf2ff33ff9xxxxxxxxxxxxxxxxce8@exchange2016.com\u003e",
"\u003c6c7f6d14axxxxxxxxxxxxxxxx9da@exchange2016.com\u003e"
],
"emails": {
"\u003c3e563564e5cc44a6aebb26f41da9d570@exchange2016.com\u003e": {
"attachment_ids": [],
"attachments": {},
"body": "\u003chtml\u003e\r\n\u003chead\u003e\r\n\u003cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"\u003e\r\n\u003c/head\u003e\r\n\u003cbody\u003e\r\nbody\r\n\u003c/body\u003e\r\n\u003c/html\u003e\r\n",
"sender_email": "johndoe.s.n@exchange2016.com",
"sender_name": "John Doe Norcross",
"subject": "Security Meeting"
},
"\u003c6c7f6d14acca4dc8ab34fd78de50e9da@exchange2016.com\u003e": {
"attachment_ids": [],
"attachments": {},
"body": "\u003chtml\u003e\r\n\u003chead\u003e\r\n\u003cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"\u003e\r\n\u003c/head\u003e\r\n\u003cbody\u003e\r\nhello\r\n\u003c/body\u003e\r\n\u003c/html\u003e\r\n",
"sender_email": "johndoe.s.n@exchange2016.com",
"sender_name": "John Doe Norcross",
"subject": "Security Meeting"
},
"\u003cdacfdd29ab69473b8c7dad28366ca4d9@exchange2016.com\u003e": {
"attachment_ids": [],
"attachments": {},
"body": "\u003chtml\u003e\r\n\u003chead\u003e\r\n\u003cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"\u003e\r\n\u003c/head\u003e\r\n\u003cbody\u003e\r\nNone\r\n\u003c/body\u003e\r\n\u003c/html\u003e\r\n",
"sender_email": "johndoe.s.n@exchange2016.com",
"sender_name": "John Doe Norcross",
"subject": "Security Meeting"
},
"\u003cf2ff33ff93104e74b33f0371b655ace8@exchange2016.com\u003e": {
"attachment_ids": [],
"attachments": {},
"body": "\u003chtml\u003e\r\n\u003chead\u003e\r\n\u003cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"\u003e\r\n\u003c/head\u003e\r\n\u003cbody\u003e\r\n\u003c/body\u003e\r\n\u003c/html\u003e\r\n",
"sender_email": "johndoe.s.n@exchange2016.com",
"sender_name": "John Doe Norcross",
"subject": "Security Meeting"
}
},
"src_folder": "Top of Information Store/Inbox"
},
"dst_folder": "Top of Information Store/Notes",
"inputs": {
"inputs": {
"exchange_delete_source_folder": false,
"exchange_destination_folder_path": "Top of Information Store/Notes",
"exchange_email": "johndoe.s@exchange2016.com",
"exchange_message_ids": null,
"exchange_end_date": null,
"exchange_folder_path": null,
"exchange_force_delete_subfolders": false,
"exchange_has_attachments": null,
"exchange_message_subject": "Security Meeting",
"exchange_num_emails": null,
"exchange_order_by_recency": null,
"exchange_search_subfolders": null,
"exchange_sender": null,
"exchange_start_date": null
}
},
"metrics": {
"execution_time_ms": 10386,
"host": "exchange2016",
"package": "fn-exchange",
"package_version": "1.0.5",
"timestamp": "2023-02-28 19:55:32",
"version": "1.0"
},
"reason": null,
"src_folder": "Top of Information Store/Inbox",
"success": true,
"version": "1.0"
}
Example Pre-Process Script:
# For information on input values, read tooltips
inputs.exchange_email_operation = "MOVED"
inputs.exchange_delete_source_folder = False
inputs.exchange_folder_path = getattr(playbook.inputs, "exchange_folder_path", None)
inputs.exchange_destination_folder_path = getattr(playbook.inputs, "exchange_destination_folder_path", None)
inputs.exchange_force_delete_subfolders = getattr(playbook.inputs, "exchange_force_delete_subfolders", False)
inputs.exchange_email = getattr(playbook.inputs, "exchange_email", None)
inputs.exchange_email_ids = getattr(playbook.inputs, "exchange_email_ids", None)
inputs.exchange_sender = getattr(playbook.inputs, "exchange_sender", None)
inputs.exchange_message_subject = getattr(playbook.inputs, "exchange_message_subject", None)
inputs.exchange_start_date = getattr(playbook.inputs, "exchange_start_date", None)
inputs.exchange_end_date = getattr(playbook.inputs, "exchange_end_date", None)
inputs.exchange_num_emails = getattr(playbook.inputs, "exchange_num_emails", None)
inputs.exchange_order_by_recency = getattr(playbook.inputs, "exchange_order_by_recency", None)
inputs.exchange_search_subfolders = getattr(playbook.inputs, "exchange_search_subfolders", None)
inputs.exchange_has_attachments = getattr(playbook.inputs, "exchange_has_attachments", None)
if playbook.inputs.exchange_message_body and playbook.inputs.exchange_message_body.content:
inputs.exchange_message_body = playbook.inputs.exchange_message_body.content
Push Emails to DataTables Script:
'''
Example function results:
------------------------
{
'email_ids': ['id1', 'idN'],
'emails': {
'id1': {
'subject': 'Email Subject',
'body': 'Subject body in HTML',
'mime_content': mime content of message
'sender_name': 'FirstName LastName',
'sender_email': 'example@example.com',
'attachment_ids': ['attachment_id1', 'attachment_id2'],
'attachments': {
'attachment_id1': {
'attachment_name': 'attachment.xslx',
'attachment_content_type': 'spreadsheet',
'attachment_size': '8842',
'attachment_base64': 'attachment encoded in base 64'},
'attachment_id2': {
'attachment_name': '...',
'attachment_content_type': '...',
'attachment_size': '...',
'attachment_base64': 'attachment encoded in base 64'}}},
'''
# Enable to add all information to a datatable found in the Exchange tab.
enable_write_to_datatables = True
# Enable to add attachments found as a base64 encoded value. This option only works when enable_write_to_datatables is set to False
enable_add_attachment_value = False
results = playbook.functions.results.output_exchange_emails
from datetime import datetime
fail_reason = results.get("reason")
content = results.get("content")
emails = content.get("emails")
email_ids = content.get("email_ids")
status_colour_map = {
"QUERIED" : "#B0C4DE", # LightSteelBlue
"MOVED" : "#B8860B", # DarkGoldenrod
"TRASHED" : "#CD5C5C", # IndianRed
"DELETED" : "#B22222"} # Firebrick
if not results.get("success"):
text = u"Unable to find emails"
if fail_reason:
text = u"{0}:\n\tFailure reason: {1}".format(text, fail_reason)
noteText = helper.createRichText(text)
incident.addNote(noteText)
else:
for email_id in email_ids:
email = emails.get(email_id)
attachment_ids = email.get('attachment_ids')
if enable_write_to_datatables:
email_status = results.get("inputs").get("inputs").get("exchange_email_operation")
email_status = u"""<p style= "color:{color}">{status} </p>""".format(color=status_colour_map[email_status], status=email_status)
message_row = incident.addRow("exchange_email_information_dt")
message_row.exchange_date_of_retrieval = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
message_row.exchange_dt_message_id = email_id
message_row.exchange_dt_recipient_email = email.get("sender_email", "-")
message_row.exchange_dt_sender_email = playbook.inputs.exchange_email
message_row.exchange_dt_email_status = helper.createRichText(email_status)
message_row.exchange_dt_message_subject = email.get("subject", "-")
message_row.exchange_dt_count_attachments = len(attachment_ids)
else:
attachments = email.get('attachments')
if email.get("sender_name"):
incident.addArtifact('Email Sender Name', email['sender_name'], 'Sender name for email {}'.format(email_id))
if email.get("sender_email"):
incident.addArtifact('Email Sender', email['sender_email'], 'Sender email address for email {}'.format(email_id))
if email.get("subject"):
incident.addArtifact('Email Subject', email['subject'], 'Email subject for email {}'.format(email_id))
if email.get("body"):
incident.addArtifact('Email Body', email['body'], 'Email body in HTML for email {}'.format(email_id))
for attachment_id in attachment_ids:
attachment = attachments.get(attachment_id)
incident.addArtifact('Email Attachment Name', attachment['attachment_name'], 'Attachment name for attachment {} from email {}'.format(attachment_id, email_id))
if enable_add_attachment_value:
incident.addArtifact('Email Attachment', attachment['attachment_base64'], 'Attachment file {} base64 encoded : {}'.format(attachment['attachment_name'], attachment['attachment_base64']))
Function - Exchange Send Email¶
Send an email to a list of recipients. Multiple recipients can be specified in a comma seperated fashion. The email being sent can now be stored in a data-table available under the Exchange incident tab. The ability to store information as artifacts is also retained. This can be turned on from within the Process Sent Email
script of this playbook.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
Yes |
|
Email account that is used |
|
|
Yes |
|
Comma separated list of emails |
|
|
No |
|
Text for the message body of an email to query or to send, depending on the function. |
|
|
No |
|
Text for the subject of an email to query or send depending on the function. |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": {
"msg_body": "Happy to announce that we have successfully cancelled your insurance",
"msg_subject": "Cancellation request",
"recipients": "johndoe.s@exchange2016.com",
"sender": "johndoe.s.n@exchange2016.com"
},
"inputs": {
"inputs": {
"exchange_email": "johndoe.s.n@exchange2016.com",
"exchange_email_recipients": "johndoe.s@exchange2016.com",
"exchange_message_body": "Happy to announce that we have successfully cancelled your insurance",
"exchange_message_subject": "Cancellation request"
}
},
"metrics": {
"execution_time_ms": 3496,
"host": "exchange2016",
"package": "fn-exchange",
"package_version": "1.0.5",
"timestamp": "2023-02-28 20:10:41",
"version": "1.0"
},
"msg_body": "Happy to announce that we have successfully cancelled your insurance",
"msg_subject": "Cancellation request",
"raw": "{\"recipients\": \"johndoe.s@exchange2016.com\", \"sender\": \"johndoe.s.n@exchange2016.com\", \"msg_subject\": \"Cancellation request\", \"msg_body\": \"Happy to announce that we have successfully cancelled your insurance\"}",
"reason": null,
"recipients": "johndoe.s@exchange2016.com",
"sender": "johndoe.s.n@exchange2016.com",
"success": true,
"version": "1.0"
}
Example Pre-Process Script:
# Set inputs
inputs.exchange_email = getattr(playbook.inputs, "exchange_email", None)
inputs.exchange_message_subject = getattr(playbook.inputs, "exchange_message_subject", None)
inputs.exchange_email_recipients = getattr(playbook.inputs, "exchange_email_recipients", None)
if playbook.inputs.exchange_message_body and playbook.inputs.exchange_message_body.content:
inputs.exchange_message_body = playbook.inputs.exchange_message_body.content
Example Post-Process Script:
'''
Example
-------
response = {
'recipients': ['user1@example.com', 'user2@example.com'],
'sender': 'sender@example.com',
'subject': 'Subject',
'body': 'HTML Body'}
'''
# Enable to write the information from the email to the data-table
enable_write_to_datatables = True
from datetime import datetime
results = playbook.functions.results.output_exchange_send_email
content = results.get("content")
if not results.get("success"):
text = u"Unable to send email"
fail_reason = results.get("reason")
if fail_reason:
text = u"{0}:\n\tFailure reason: {1}".format(text, fail_reason)
noteText = helper.createRichText(text)
incident.addNote(noteText)
else:
if enable_write_to_datatables:
message_row = incident.addRow("exchange_email_information_dt")
message_row.exchange_date_of_retrieval = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
message_row.exchange_dt_recipient_email = str(content.get('recipients'))
message_row.exchange_dt_sender_email = content.get('sender')
message_row.exchange_dt_email_status = helper.createRichText(u"""<p style= "color:{color}">{status} </p>""".format(
color="#228B22", status="SENT"))
message_row.exchange_dt_message_subject = content.get("msg_subject", "-")
message_row.exchange_dt_count_attachments = 0
else:
text = "<b>Exchange email:</b><br />"
text += f"<br />From: {content.get('sender')}"
text += f"<br />Recipients: {content.get('recipients')}"
text += f"<br />Subject: {content.get('msg_subject')}"
text += f"<br />Body: {content.get('msg_body')}"
noteText = helper.createRichText(text)
incident.addNote(noteText)
Data Table - Email Information¶
API Name:¶
exchange_email_information_dt
Columns:¶
Column Name |
API Access Name |
Type |
Tooltip |
---|---|---|---|
Attachments |
|
|
Number of attachments in the email |
Date of Retrieval |
|
|
Date the email was retrieved from the mailbox. Not to be confused with email received date. |
Message ID |
|
|
Unique ID of the message |
Message Subject |
|
|
Subject of the email |
Recipient Email Address |
|
|
Email address of the Recipient |
Sender Email Address |
|
|
Email address of the sender |
Status |
|
|
Queried / Sent / Moved / Deleted / Trashed (depends on the action being performed) |
Data Table - Meeting Information¶
API Name:¶
exchange_dt_meeting_information
Columns:¶
Column Name |
API Access Name |
Type |
Tooltip |
---|---|---|---|
Created Time |
|
|
Date and time of when the meeting was created |
End Time |
|
|
Meeting end date and time |
Location |
|
|
Online meeting URL or offline meeting phsical location |
Mandatory Attendees |
|
|
Required participants |
Meeting Subject |
|
|
Subject of the invite |
Optional Attendees |
|
|
Optional participants |
Start Time |
|
|
Meeting start date and time |
Playbook¶
Playbook Name |
Object |
API Name |
---|---|---|
Playbooks: Exchange Create Meeting |
incident |
|
Playbooks: Exchange Delete Emails |
incident |
|
Playbooks: Exchange Find Emails |
incident |
|
Playbooks: Exchange Move Contents and Delete Folder |
incident |
|
Playbooks: Exchange Move Emails |
incident |
|
Playbooks: Exchange Retrieve Mailbox Information |
incident |
|
Playbooks: Exchange Send Email |
incident |
|
Troubleshooting & Support¶
Refer to the documentation listed in the Requirements section for troubleshooting information.
For Support¶
This is an IBM supported app. Please search ibm.com/mysupport for assistance.