From 58c8d88ff80eaa5e520db76a345efcf136cb06c3 Mon Sep 17 00:00:00 2001 From: Sean Whalen Date: Wed, 17 Jul 2019 11:06:53 -0400 Subject: [PATCH] 6.5.0 --- _modules/index.html | 4 +- _modules/parsedmarc.html | 1014 +++++++----------------------- _modules/parsedmarc/elastic.html | 4 +- _modules/parsedmarc/splunk.html | 4 +- _modules/parsedmarc/utils.html | 27 +- _sources/index.rst.txt | 16 +- _static/documentation_options.js | 2 +- genindex.html | 16 +- index.html | 145 +++-- objects.inv | 5 +- py-modindex.html | 4 +- search.html | 4 +- searchindex.js | 2 +- 13 files changed, 338 insertions(+), 909 deletions(-) diff --git a/_modules/index.html b/_modules/index.html index be25429..de07085 100644 --- a/_modules/index.html +++ b/_modules/index.html @@ -8,7 +8,7 @@ - Overview: module code — parsedmarc 6.4.2 documentation + Overview: module code — parsedmarc 6.5.0 documentation @@ -58,7 +58,7 @@
- 6.4.2 + 6.5.0
diff --git a/_modules/parsedmarc.html b/_modules/parsedmarc.html index 8c18bb8..5103bad 100644 --- a/_modules/parsedmarc.html +++ b/_modules/parsedmarc.html @@ -8,7 +8,7 @@ - parsedmarc — parsedmarc 6.4.2 documentation + parsedmarc — parsedmarc 6.5.0 documentation @@ -58,7 +58,7 @@
- 6.4.2 + 6.5.0
@@ -165,27 +165,20 @@ import binascii import email import tempfile -import socket -from email.mime.application import MIMEApplication -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText import email.utils -import smtplib -from ssl import SSLError, CertificateError, create_default_context -import time +import mailparser from expiringdict import ExpiringDict import xmltodict -import imapclient -import imapclient.exceptions -import mailparser +from mailsuite.imap import IMAPClient +from mailsuite.smtp import send_email from parsedmarc.utils import get_base_domain, get_ip_address_info from parsedmarc.utils import is_outlook_msg, convert_outlook_msg from parsedmarc.utils import timestamp_to_human, human_timestamp_to_datetime from parsedmarc.utils import parse_email -__version__ = "6.4.2" +__version__ = "6.5.0" logging.basicConfig( format='%(levelname)8s:%(filename)s:%(lineno)d:' @@ -210,14 +203,6 @@ """Raised whenever the parser fails for some reason""" -
[docs]class IMAPError(RuntimeError): - """Raised when an IMAP error occurs"""
- - -
[docs]class SMTPError(RuntimeError): - """Raised when a SMTP error occurs"""
- -
[docs]class InvalidDMARCReport(ParserError): """Raised when an invalid DMARC report is encountered"""
@@ -230,14 +215,15 @@ """Raised when an invalid DMARC forensic report is encountered""" -def _parse_report_record(record, nameservers=None, dns_timeout=2.0, - parallel=False): +def _parse_report_record(record, offline=False, nameservers=None, + dns_timeout=2.0, parallel=False): """ Converts a record from a DMARC aggregate report into a more consistent format Args: record (OrderedDict): The record to convert + offline (bool): Do not query online for geolocation or DNS nameservers (list): A list of one or more nameservers to use (Cloudflare's public DNS resolvers by default) dns_timeout (float): Sets the DNS timeout in seconds @@ -253,6 +239,7 @@ new_record = OrderedDict() new_record_source = get_ip_address_info(record["row"]["source_ip"], cache=IP_ADDRESS_CACHE, + offline=offline, nameservers=nameservers, timeout=dns_timeout, parallel=parallel) @@ -357,12 +344,13 @@ return new_record -
[docs]def parse_aggregate_report_xml(xml, nameservers=None, timeout=2.0, - parallel=False): +
[docs]def parse_aggregate_report_xml(xml, offline=False, nameservers=None, + timeout=2.0, parallel=False): """Parses a DMARC XML report string and returns a consistent OrderedDict Args: xml (str): A string of DMARC aggregate report XML + offline (bool): Do not query online for geolocation or DNS nameservers (list): A list of one or more nameservers to use (Cloudflare's public DNS resolvers by default) timeout (float): Sets the DNS timeout in seconds @@ -457,6 +445,7 @@ if type(report["record"]) == list: for record in report["record"]: report_record = _parse_report_record(record, + offline=offline, nameservers=nameservers, dns_timeout=timeout, parallel=parallel) @@ -464,6 +453,7 @@ else: report_record = _parse_report_record(report["record"], + offline=offline, nameservers=nameservers, dns_timeout=timeout, parallel=parallel) @@ -532,13 +522,15 @@ return xml
-
[docs]def parse_aggregate_report_file(_input, nameservers=None, dns_timeout=2.0, +
[docs]def parse_aggregate_report_file(_input, offline=False, nameservers=None, + dns_timeout=2.0, parallel=False): """Parses a file at the given path, a file-like object. or bytes as a aggregate DMARC report Args: _input: A path to a file, a file like object, or bytes + offline (bool): Do not query online for geolocation or DNS nameservers (list): A list of one or more nameservers to use (Cloudflare's public DNS resolvers by default) dns_timeout (float): Sets the DNS timeout in seconds @@ -550,6 +542,7 @@ xml = extract_xml(_input) return parse_aggregate_report_xml(xml, + offline=offline, nameservers=nameservers, timeout=dns_timeout, parallel=parallel)
@@ -666,7 +659,7 @@
[docs]def parse_forensic_report(feedback_report, sample, msg_date, - nameservers=None, dns_timeout=2.0, + offline=False, nameservers=None, dns_timeout=2.0, strip_attachment_payloads=False, parallel=False): """ @@ -674,6 +667,7 @@ Args: feedback_report (str): A message's feedback report as a string + offline (bool): Do not query online for geolocation or DNS sample (str): The RFC 822 headers or RFC 822 message sample msg_date (str): The message's date header nameservers (list): A list of one or more nameservers to use @@ -724,6 +718,7 @@ ip_address = parsed_report["source_ip"] parsed_report_source = get_ip_address_info(ip_address, + offline=offline, nameservers=nameservers, timeout=dns_timeout, parallel=parallel) @@ -825,13 +820,15 @@ return csv_file.getvalue()
-
[docs]def parse_report_email(input_, nameservers=None, dns_timeout=2.0, - strip_attachment_payloads=False, parallel=False): +
[docs]def parse_report_email(input_, offline=False, nameservers=None, + dns_timeout=2.0, strip_attachment_payloads=False, + parallel=False): """ Parses a DMARC report from an email Args: input_: An emailed DMARC report in RFC 822 format, as bytes or a string + offline (bool): Do not query online for geolocation on DNS nameservers (list): A list of one or more nameservers to use dns_timeout (float): Sets the DNS timeout in seconds strip_attachment_payloads (bool): Remove attachment payloads from @@ -849,7 +846,7 @@ if is_outlook_msg(input_): input_ = convert_outlook_msg(input_) if type(input_) == bytes: - input_ = input_.decode(encoding="utf8") + input_ = input_.decode(encoding="utf8", errors="replace") msg = mailparser.parse_from_string(input_) msg_headers = json.loads(msg.headers_json) date = email.utils.format_datetime(datetime.utcnow()) @@ -897,6 +894,7 @@ ns = nameservers aggregate_report = parse_aggregate_report_file( payload, + offline=offline, nameservers=ns, dns_timeout=dns_timeout, parallel=parallel) @@ -924,6 +922,7 @@ feedback_report, sample, date, + offline=offline, nameservers=nameservers, dns_timeout=dns_timeout, strip_attachment_payloads=strip_attachment_payloads, @@ -947,7 +946,8 @@
[docs]def parse_report_file(input_, nameservers=None, dns_timeout=2.0, - strip_attachment_payloads=False, parallel=False): + strip_attachment_payloads=False, + offline=False, parallel=False): """Parses a DMARC aggregate or forensic file at the given path, a file-like object. or bytes @@ -958,12 +958,14 @@ dns_timeout (float): Sets the DNS timeout in seconds strip_attachment_payloads (bool): Remove attachment payloads from forensic report results + offline (bool): Do not make online queries for geolocation or DNS parallel (bool): Parallel processing Returns: OrderedDict: The parsed DMARC report """ if type(input_) == str: + logger.debug("Parsing {0}".format(input_)) file_object = open(input_, "rb") elif type(input_) == bytes: file_object = BytesIO(input_) @@ -972,7 +974,9 @@ content = file_object.read() try: - report = parse_aggregate_report_file(content, nameservers=nameservers, + report = parse_aggregate_report_file(content, + offline=offline, + nameservers=nameservers, dns_timeout=dns_timeout, parallel=parallel) results = OrderedDict([("report_type", "aggregate"), @@ -981,6 +985,7 @@ try: sa = strip_attachment_payloads results = parse_report_email(content, + offline=offline, nameservers=nameservers, dns_timeout=dns_timeout, strip_attachment_payloads=sa, @@ -1011,39 +1016,38 @@ return capabilities
-
[docs]def get_dmarc_reports_from_inbox(host=None, +
[docs]def get_dmarc_reports_from_inbox(connection=None, + host=None, user=None, password=None, - connection=None, port=None, ssl=True, - ssl_context=None, - move_supported=None, + verify=True, reports_folder="INBOX", archive_folder="Archive", delete=False, test=False, + offline=False, nameservers=None, dns_timeout=6.0, strip_attachment_payloads=False, results=None): """ - Fetches and parses DMARC reports from sn inbox + Fetches and parses DMARC reports from an inbox Args: + connection: An IMAPClient connection to reuse host: The mail server hostname or IP address user: The mail server user password: The mail server password - connection: An IMAPCLient connection to reuse port: The mail server port ssl (bool): Use SSL/TLS - ssl_context (SSLContext): A SSL context - move_supported: Indicate if the IMAP server supports the MOVE command - (autodetect if None) + verify (bool): Verify SSL/TLS certificate reports_folder: The IMAP folder where reports can be found archive_folder: The folder to move processed mail to delete (bool): Delete messages after processing them test (bool): Do not move or delete messages after processing them + offline (bool): Do not query onfline for geolocation or DNS nameservers (list): A list of DNS nameservers to query dns_timeout (float): Set the DNS query timeout strip_attachment_payloads (bool): Remove attachment payloads from @@ -1053,12 +1057,6 @@ Returns: OrderedDict: Lists of ``aggregate_reports`` and ``forensic_reports`` """ - - def chunks(l, n): - """Yield successive n-sized chunks from l.""" - for i in range(0, len(l), n): - yield l[i:i + n] - if delete and test: raise ValueError("delete and test options are mutually exclusive") @@ -1078,373 +1076,122 @@ aggregate_reports = results["aggregate_reports"].copy() forensic_reports = results["forensic_reports"].copy() - try: - if connection: - server = connection - else: - if not ssl: - logger.debug("Connecting to IMAP over plain text") - if ssl_context is None: - ssl_context = create_default_context() - server = imapclient.IMAPClient(host, - port=port, - ssl=ssl, - ssl_context=ssl_context, - use_uid=True) - server.login(user, password) + if connection: + server = connection + else: + server = IMAPClient(host, user, password, port=port, + ssl=ssl, verify=verify, + initial_folder=reports_folder) - if move_supported is None: - server_capabilities = get_imap_capabilities(server) - move_supported = "MOVE" in server_capabilities + server.create_folder(archive_folder) + server.create_folder(aggregate_reports_folder) + server.create_folder(forensic_reports_folder) + server.create_folder(invalid_reports_folder) - def delete_messages(msg_uids): - logger.debug("Deleting message UID(s) {0}".format(",".join( - str(uid) for uid in msg_uids))) - if type(msg_uids) == str or type(msg_uids) == int: - msg_uids = [int(msg_uids)] + messages = server.search() + total_messages = len(messages) + logger.debug("Found {0} messages in {1}".format(len(messages), + reports_folder)) + for i in range(len(messages)): + msg_uid = messages[i] + logger.debug("Processing message {0} of {1}: UID {2}".format( + i+1, total_messages, msg_uid - server.delete_messages(msg_uids, silent=True) - server.expunge(msg_uids) - - def move_messages(msg_uids, folder): - if type(msg_uids) == str or type(msg_uids) == int: - msg_uids = [int(msg_uids)] - for chunk in chunks(msg_uids, 100): - if move_supported: - logger.debug("Moving message UID(s) {0} to {1}".format( - ",".join(str(uid) for uid in chunk), folder - )) - try: - server.move(chunk, folder) - except imapclient.exceptions.IMAPClientError as e: - e = e.__str__().lstrip("b'").rstrip( - "'").rstrip(".") - message = "Error moving message UID" - e = "{0} {1}: " "{2}".format(message, msg_uid, e) - logger.debug("IMAP error: {0}".format(e)) - logger.debug( - "Copying message UID(s) {0} to {1}".format( - ",".join(str(uid) for uid in chunk), folder - )) - server.copy(msg_uids, folder) - delete_messages(msg_uids) - else: - logger.debug("Copying message UID(s) {0} to {1}".format( - ",".join(str(uid) for uid in chunk), folder - )) - server.copy(msg_uids, folder) - delete_messages(msg_uids) - - if not server.folder_exists(archive_folder): - logger.debug("Creating IMAP folder: {0}".format(archive_folder)) - server.create_folder(archive_folder) + )) + msg_content = server.fetch_message(msg_uid, parse=False) + sa = strip_attachment_payloads try: - # Test subfolder creation - if not server.folder_exists(aggregate_reports_folder): - server.create_folder(aggregate_reports_folder) - logger.debug( - "Creating IMAP folder: {0}".format( - aggregate_reports_folder)) - except imapclient.exceptions.IMAPClientError: - # Only replace / with . when . doesn't work - # This usually indicates a dovecot IMAP server - aggregate_reports_folder = aggregate_reports_folder.replace("/", - ".") - forensic_reports_folder = forensic_reports_folder.replace("/", - ".") - invalid_reports_folder = invalid_reports_folder.replace("/", - ".") - subfolders = [aggregate_reports_folder, - forensic_reports_folder, - invalid_reports_folder] + parsed_email = parse_report_email(msg_content, + nameservers=nameservers, + dns_timeout=dns_timeout, + offline=offline, + strip_attachment_payloads=sa) + if parsed_email["report_type"] == "aggregate": + aggregate_reports.append(parsed_email["report"]) + aggregate_report_msg_uids.append(msg_uid) + elif parsed_email["report_type"] == "forensic": + forensic_reports.append(parsed_email["report"]) + forensic_report_msg_uids.append(msg_uid) + except InvalidDMARCReport as error: + logger.warning(error.__str__()) + if not test: + if delete: + logger.debug( + "Deleting message UID {0}".format(msg_uid)) + server.delete_messages([msg_uid]) + else: + logger.debug( + "Moving message UID {0} to {1}".format( + msg_uid, invalid_reports_folder)) + server.move_messages([msg_uid], invalid_reports_folder) - for subfolder in subfolders: - if not server.folder_exists(subfolder): + if not test: + if delete: + processed_messages = aggregate_report_msg_uids + \ + forensic_report_msg_uids + + number_of_processed_msgs = len(processed_messages) + for i in range(number_of_processed_msgs): + msg_uid = processed_messages[i] logger.debug( - "Creating IMAP folder: {0}".format(subfolder)) - server.create_folder(subfolder) - server.select_folder(reports_folder) - messages = server.search() - total_messages = len(messages) - logger.debug("Found {0} messages in IMAP folder {1}".format( - len(messages), reports_folder)) - for i in range(len(messages)): - msg_uid = messages[i] - logger.debug("Processing message {0} of {1}: UID {2}".format( - i+1, - total_messages, - msg_uid - )) - try: + "Deleting message {0} of {1}: UID {2}".format( + i + 1, number_of_processed_msgs, msg_uid)) try: - raw_msg = server.fetch(msg_uid, - ["RFC822"])[msg_uid] - msg_keys = [b'RFC822', b'BODY[NULL]', b'BODY[]'] - msg_key = '' - for key in msg_keys: - if key in raw_msg.keys(): - msg_key = key - break - raw_msg = raw_msg[msg_key] + server.delete_messages([msg_uid]) - except (ConnectionResetError, socket.error, - TimeoutError, - imapclient.exceptions.IMAPClientError) as error: - error = error.__str__().lstrip("b'").rstrip("'").rstrip( - ".") - logger.debug("IMAP error: {0}".format(error.__str__())) - logger.debug("Reconnecting to IMAP") + except Exception as e: + message = "Error deleting message UID" + e = "{0} {1}: " "{2}".format(message, msg_uid, e) + logger.error("IMAP error: {0}".format(e)) + else: + if len(aggregate_report_msg_uids) > 0: + log_message = "Moving aggregate report messages from" + logger.debug( + "{0} {1} to {2}".format( + log_message, reports_folder, + aggregate_reports_folder)) + number_of_agg_report_msgs = len(aggregate_report_msg_uids) + for i in range(number_of_agg_report_msgs): + msg_uid = aggregate_report_msg_uids[i] + logger.debug( + "Moving message {0} of {1}: UID {2}".format( + i+1, number_of_agg_report_msgs, msg_uid)) try: - server.shutdown() + server.move_messages([msg_uid], + aggregate_reports_folder) except Exception as e: - logger.debug( - "Failed to log out: {0}".format(e.__str__())) - if not ssl: - logger.debug("Connecting to IMAP over plain text") - server = imapclient.IMAPClient(host, - port=port, - ssl=ssl, - ssl_context=ssl_context, - use_uid=True) - server.login(user, password) - server.select_folder(reports_folder) - raw_msg = server.fetch(msg_uid, - ["RFC822"])[msg_uid][b"RFC822"] - - msg_content = raw_msg.decode("utf-8", errors="replace") - sa = strip_attachment_payloads - parsed_email = parse_report_email(msg_content, - nameservers=nameservers, - dns_timeout=dns_timeout, - strip_attachment_payloads=sa) - if parsed_email["report_type"] == "aggregate": - aggregate_reports.append(parsed_email["report"]) - aggregate_report_msg_uids.append(msg_uid) - elif parsed_email["report_type"] == "forensic": - forensic_reports.append(parsed_email["report"]) - forensic_report_msg_uids.append(msg_uid) - except InvalidDMARCReport as error: - logger.warning(error.__str__()) - if not test: - if delete: - logger.debug( - "Deleting message UID {0}".format(msg_uid)) - delete_messages([msg_uid]) - else: - logger.debug( - "Moving message UID {0} to {1}".format( - msg_uid, invalid_reports_folder)) - move_messages([msg_uid], invalid_reports_folder) - - if not test: - if delete: - processed_messages = aggregate_report_msg_uids + \ - forensic_report_msg_uids - - number_of_processed_msgs = len(processed_messages) - for i in range(number_of_processed_msgs): - msg_uid = processed_messages[i] - logger.debug( - "Deleting message {0} of {1}: UID {2}".format( - i + 1, number_of_processed_msgs, msg_uid)) - try: - delete_messages([msg_uid]) - - except imapclient.exceptions.IMAPClientError as e: - e = e.__str__().lstrip("b'").rstrip( - "'").rstrip(".") - message = "Error deleting message UID" - e = "{0} {1}: " "{2}".format(message, msg_uid, e) + message = "Error moving message UID" + e = "{0} {1}: {2}".format(message, msg_uid, e) logger.error("IMAP error: {0}".format(e)) - except (ConnectionResetError, socket.error, - TimeoutError) as e: - logger.debug("IMAP error: {0}".format(e.__str__())) - logger.debug("Reconnecting to IMAP") - try: - server.shutdown() - except Exception as e: - logger.debug( - "Failed to log out: {0}".format(e.__str__())) - if not ssl: - logger.debug("Connecting to IMAP over plain text") - server = imapclient.IMAPClient(host, - port=port, - ssl=ssl, - ssl_context=ssl_context, - use_uid=True) - server.login(user, password) - server.select_folder(reports_folder) - delete_messages([msg_uid]) - else: - if len(aggregate_report_msg_uids) > 0: - log_message = "Moving aggregate report messages from" - logger.debug( - "{0} {1} to {2}".format( - log_message, reports_folder, - aggregate_reports_folder)) - number_of_agg_report_msgs = len(aggregate_report_msg_uids) - for i in range(number_of_agg_report_msgs): - msg_uid = aggregate_report_msg_uids[i] - logger.debug( - "Moving message {0} of {1}: UID {2}".format( - i+1, number_of_agg_report_msgs, msg_uid)) - try: - move_messages([msg_uid], - aggregate_reports_folder) - except imapclient.exceptions.IMAPClientError as e: - e = e.__str__().lstrip("b'").rstrip( - "'").rstrip(".") - message = "Error moving message UID" - e = "{0} {1}: {2}".format(message, msg_uid, e) - logger.error("IMAP error: {0}".format(e)) - except (ConnectionResetError, socket.error, - TimeoutError) as error: - logger.debug("IMAP error: {0}".format( - error.__str__())) - logger.debug("Reconnecting to IMAP") - try: - server.shutdown() - except Exception as e: - logger.debug("Failed to log out: {0}".format( - e.__str__())) - if not ssl: - logger.debug( - "Connecting to IMAP over plain text") - server = imapclient.IMAPClient( - host, - port=port, - ssl=ssl, - ssl_context=ssl_context, - use_uid=True - ) - server.login(user, password) - server.select_folder(reports_folder) - move_messages([msg_uid], - aggregate_reports_folder) + if len(forensic_report_msg_uids) > 0: + message = "Moving forensic report messages from" + logger.debug( + "{0} {1} to {2}".format(message, + reports_folder, + forensic_reports_folder)) + number_of_forensic_msgs = len(forensic_report_msg_uids) + for i in range(number_of_forensic_msgs): + msg_uid = forensic_report_msg_uids[i] + message = "Moving message" + logger.debug("{0} {1} of {2}: UID {2}".format( + message, + i + 1, number_of_forensic_msgs, msg_uid)) + try: + server.move_messages([msg_uid], + forensic_reports_folder) + except Exception as e: + e = "Error moving message UID {0}: {1}".format( + msg_uid, e) + logger.error("IMAP error: {0}".format(e)) + results = OrderedDict([("aggregate_reports", aggregate_reports), + ("forensic_reports", forensic_reports)]) - if len(forensic_report_msg_uids) > 0: - message = "Moving forensic report messages from" - logger.debug( - "{0} {1} to {2}".format(message, - reports_folder, - forensic_reports_folder)) - number_of_forensic_msgs = len(forensic_report_msg_uids) - for i in range(number_of_forensic_msgs): - msg_uid = forensic_report_msg_uids[i] - message = "Moving message" - logger.debug("{0} {1} of {2}: UID {2}".format( - message, - i + 1, number_of_forensic_msgs, msg_uid)) - try: - move_messages([msg_uid], - forensic_reports_folder) - except imapclient.exceptions.IMAPClientError as e: - e = e.__str__().lstrip("b'").rstrip( - "'").rstrip(".") - e = "Error moving message UID {0}: {1}".format( - msg_uid, e) - logger.error("IMAP error: {0}".format(e)) - except (ConnectionResetError, TimeoutError) as error: - logger.debug("IMAP error: {0}".format( - error.__str__())) - logger.debug("Reconnecting to IMAP") - try: - server.shutdown() - except Exception as e: - logger.debug("Failed to " - "disconnect: {0}".format( - e.__str__())) - if not ssl: - logger.debug( - "Connecting to IMAP over plain text") - server = imapclient.IMAPClient( - host, - port=port, - ssl=ssl, - ssl_context=ssl_context, - use_uid=True) - server.login(user, password) - server.select_folder(reports_folder) - move_messages([msg_uid], - forensic_reports_folder) + total_messages = len(server.search()) - results = OrderedDict([("aggregate_reports", aggregate_reports), - ("forensic_reports", forensic_reports)]) - - if not test and total_messages > 0: - # Process emails that came in during the last run - results = get_dmarc_reports_from_inbox( - host=host, - user=user, - password=password, - connection=connection, - port=port, - ssl=ssl, - ssl_context=ssl_context, - move_supported=move_supported, - reports_folder=reports_folder, - archive_folder=archive_folder, - delete=delete, - test=test, - nameservers=nameservers, - dns_timeout=dns_timeout, - strip_attachment_payloads=strip_attachment_payloads, - results=results - ) - - return results - except imapclient.exceptions.IMAPClientError as error: - error = error.__str__().lstrip("b'").rstrip("'").rstrip(".") - # Workaround for random Exchange/Office365 IMAP errors - if "unexpected response" in error or "BAD" in error: - sleep_minutes = 5 - logger.debug( - "{0}. " - "Waiting {1} minutes before trying again".format( - error, - sleep_minutes)) - time.sleep(sleep_minutes * 60) - results = get_dmarc_reports_from_inbox( - host=host, - user=user, - password=password, - connection=connection, - port=port, - ssl=ssl, - ssl_context=ssl_context, - move_supported=move_supported, - reports_folder=reports_folder, - archive_folder=archive_folder, - delete=delete, - test=test, - nameservers=nameservers, - dns_timeout=dns_timeout, - strip_attachment_payloads=strip_attachment_payloads, - results=results - ) - - return results - - raise IMAPError(error) - except socket.gaierror: - raise IMAPError("DNS resolution failed") - except ConnectionRefusedError: - raise IMAPError("Connection refused") - except ConnectionResetError: - sleep_minutes = 5 - logger.debug( - "Connection reset. " - "Waiting {0} minutes before trying again".format(sleep_minutes)) - time.sleep(sleep_minutes * 60) + if not test and total_messages > 0: + # Process emails that came in during the last run results = get_dmarc_reports_from_inbox( - host=host, - user=user, - password=password, - connection=connection, - port=port, - ssl=ssl, - ssl_context=ssl_context, - move_supported=move_supported, + connection=server, reports_folder=reports_folder, archive_folder=archive_folder, delete=delete, @@ -1455,15 +1202,56 @@ results=results ) - return results - except ConnectionAbortedError: - raise IMAPError("Connection aborted") - except TimeoutError: - raise IMAPError("Connection timed out") - except SSLError as error: - raise IMAPError("SSL error: {0}".format(error.__str__())) - except CertificateError as error: - raise IMAPError("Certificate error: {0}".format(error.__str__()))
+ return results
+ + +
[docs]def watch_inbox(host, username, password, callback, port=None, ssl=True, + verify=True, reports_folder="INBOX", + archive_folder="Archive", delete=False, test=False, + idle_timeout=30, offline=False, nameservers=None, + dns_timeout=6.0, strip_attachment_payloads=False): + """ + Use an IDLE IMAP connection to parse incoming emails, and pass the results + to a callback function + Args: + host: The mail server hostname or IP address + username: The mail server username + password: The mail server password + callback: The callback function to receive the parsing results + port: The mail server port + ssl (bool): Use SSL/TLS + verify (bool): Verify the TLS/SSL certificate + reports_folder: The IMAP folder where reports can be found + archive_folder: The folder to move processed mail to + delete (bool): Delete messages after processing them + test (bool): Do not move or delete messages after processing them + idle_timeout (int): Number of seconds to wait for a IMAP IDLE response + offline (bool): Do not query online for geolocation or DNS + nameservers (list): A list of one or more nameservers to use + (Cloudflare's public DNS resolvers by default) + dns_timeout (float): Set the DNS query timeout + strip_attachment_payloads (bool): Replace attachment payloads in + forensic report samples with None + """ + sa = strip_attachment_payloads + + def idle_callback(connection): + res = get_dmarc_reports_from_inbox(connection=connection, + reports_folder=reports_folder, + archive_folder=archive_folder, + delete=delete, + test=test, + offline=offline, + nameservers=nameservers, + dns_timeout=dns_timeout, + strip_attachment_payloads=sa) + callback(res) + + IMAPClient(host=host, username=username, password=password, + port=port, ssl=ssl, verify=verify, + initial_folder=reports_folder, + idle_callback=idle_callback, + idle_timeout=idle_timeout)
[docs]def save_output(results, output_directory="output"): @@ -1573,9 +1361,11 @@ return storage.getvalue()
-
[docs]def email_results(results, host, mail_from, mail_to, port=0, - ssl=False, user=None, password=None, subject=None, - attachment_filename=None, message=None, ssl_context=None): +
[docs]def email_results(results, host, mail_from, mail_to, + mail_cc=None, mail_bcc=None, port=0, + require_encryption=False, verify=True, + username=None, password=None, subject=None, + attachment_filename=None, message=None): """ Emails parsing results as a zip file @@ -1583,15 +1373,17 @@ results (OrderedDict): Parsing results host: Mail server hostname or IP address mail_from: The value of the message from header - mail_to : A list of addresses to mail to + mail_to (list): A list of addresses to mail to + mail_cc (list): A list of addresses to CC + mail_bcc (list): A list addresses to BCC port (int): Port to use - ssl (bool): Require a SSL connection from the start - user: An optional username - password: An optional password - subject: Overrides the default message subject - attachment_filename: Override the default attachment filename - message: Override the default plain text body - ssl_context: SSL context options + require_encryption (bool): Require a secure connection from the start + verify (bool): verify the SSL/TLS certificate + username (str): An optional username + password (str): An optional password + subject (str): Overrides the default message subject + attachment_filename (str): Override the default attachment filename + message (str: Override the default plain text body """ logging.debug("Emailing report to: {0}".format(",".join(mail_to))) date_string = datetime.now().strftime("%Y-%m-%d") @@ -1604,380 +1396,18 @@ assert isinstance(mail_to, list) - msg = MIMEMultipart() - msg['From'] = mail_from - msg['To'] = ", ".join(mail_to) - msg['Date'] = email.utils.formatdate(localtime=True) - msg['Subject'] = subject or "DMARC results for {0}".format(date_string) - text = message or "Please see the attached zip file\n" - - msg.attach(MIMEText(text)) - + if subject is None: + subject = "DMARC results for {0}".format(date_string) + if message is None: + message = "DMARC results for {0}".format(date_string) zip_bytes = get_report_zip(results) - part = MIMEApplication(zip_bytes, Name=filename) + attachments = [(filename, zip_bytes)] - part['Content-Disposition'] = 'attachment; filename="{0}"'.format(filename) - msg.attach(part) - - try: - if ssl_context is None: - ssl_context = create_default_context() - if ssl: - server = smtplib.SMTP_SSL(host, port=port, context=ssl_context) - server.connect(host, port) - server.ehlo_or_helo_if_needed() - else: - server = smtplib.SMTP(host, port=port) - server.connect(host, port) - server.ehlo_or_helo_if_needed() - if server.has_extn("starttls"): - server.starttls(context=ssl_context) - server.ehlo() - else: - logger.warning("SMTP server does not support STARTTLS. " - "Proceeding in plain text!") - if user and password: - server.login(user, password) - server.sendmail(mail_from, mail_to, msg.as_string()) - except smtplib.SMTPException as error: - error = error.__str__().lstrip("b'").rstrip("'").rstrip(".") - raise SMTPError(error) - except socket.gaierror: - raise SMTPError("DNS resolution failed") - except ConnectionRefusedError: - raise SMTPError("Connection refused") - except ConnectionResetError: - raise SMTPError("Connection reset") - except ConnectionAbortedError: - raise SMTPError("Connection aborted") - except TimeoutError: - raise SMTPError("Connection timed out") - except SSLError as error: - raise SMTPError("SSL error: {0}".format(error.__str__())) - except CertificateError as error: - raise SMTPError("Certificate error: {0}".format(error.__str__()))
- - -
[docs]def watch_inbox(host, username, password, callback, port=None, ssl=True, - ssl_context=None, reports_folder="INBOX", - archive_folder="Archive", delete=False, test=False, wait=30, - nameservers=None, dns_timeout=6.0, - strip_attachment_payloads=False): - """ - Use an IDLE IMAP connection to parse incoming emails, and pass the results - to a callback function - - Args: - host: The mail server hostname or IP address - username: The mail server username - password: The mail server password - callback: The callback function to receive the parsing results - port: The mail server port - ssl (bool): Use SSL/TLS - ssl_context (SSLContext): A SSL context - reports_folder: The IMAP folder where reports can be found - archive_folder: The folder to move processed mail to - delete (bool): Delete messages after processing them - test (bool): Do not move or delete messages after processing them - wait (int): Number of seconds to wait for a IMAP IDLE response - nameservers (list): A list of one or more nameservers to use - (Cloudflare's public DNS resolvers by default) - dns_timeout (float): Set the DNS query timeout - strip_attachment_payloads (bool): Replace attachment payloads in - forensic report samples with None - """ - rf = reports_folder - af = archive_folder - ns = nameservers - dt = dns_timeout - if ssl_context is None: - ssl_context = create_default_context() - server = imapclient.IMAPClient(host, port=port, ssl=ssl, - ssl_context=ssl_context, - use_uid=True) - - try: - server.login(username, password) - imap_capabilities = get_imap_capabilities(server) - if "IDLE" not in imap_capabilities: - raise IMAPError("Cannot watch inbox: IMAP server does not support " - "the IDLE command") - - ms = "MOVE" in imap_capabilities - server.select_folder(rf) - idle_start_time = time.monotonic() - server.idle() - - except imapclient.exceptions.IMAPClientError as error: - error = error.__str__().replace("b'", "").replace("'", "") - # Workaround for random Exchange/Office365 IMAP errors - if "unexpected response" in error or "BAD" in error: - sleep_minutes = 5 - logger.debug( - "{0}. " - "Waiting {1} minutes before trying again".format( - error, - sleep_minutes)) - logger.debug("Reconnecting watcher") - try: - server.logout() - except Exception as e: - logger.debug("Failed to log out: {0}".format(e.__str__())) - server = imapclient.IMAPClient(host) - server.login(username, password) - server.select_folder(rf) - idle_start_time = time.monotonic() - ms = "MOVE" in get_imap_capabilities(server) - sa = strip_attachment_payloads - res = get_dmarc_reports_from_inbox(connection=server, - move_supported=ms, - reports_folder=rf, - archive_folder=af, - delete=delete, - test=test, - nameservers=ns, - dns_timeout=dt, - strip_attachment_payloads=sa) - callback(res) - server.idle() - else: - raise IMAPError(error) - except socket.gaierror: - raise IMAPError("DNS resolution failed") - except ConnectionRefusedError: - raise IMAPError("Connection refused") - except ConnectionResetError: - logger.debug("IMAP error: Connection reset") - logger.debug("Reconnecting watcher") - try: - server.shutdown() - except Exception as e: - logger.debug("Failed to disconnect: {0}".format(e.__str__())) - server = imapclient.IMAPClient(host) - server.login(username, password) - server.select_folder(rf) - idle_start_time = time.monotonic() - ms = "MOVE" in get_imap_capabilities(server) - res = get_dmarc_reports_from_inbox(connection=server, - move_supported=ms, - reports_folder=rf, - archive_folder=af, - delete=delete, - test=test, - nameservers=ns, - dns_timeout=dt) - callback(res) - server.idle() - except KeyError: - logger.debug("IMAP error: Server returned unexpected result") - logger.debug("Reconnecting watcher") - try: - server.logout() - except Exception as e: - logger.debug("Failed to log out: {0}".format(e.__str__())) - server = imapclient.IMAPClient(host) - server.login(username, password) - server.select_folder(rf) - idle_start_time = time.monotonic() - ms = "MOVE" in get_imap_capabilities(server) - res = get_dmarc_reports_from_inbox(connection=server, - move_supported=ms, - reports_folder=rf, - archive_folder=af, - delete=delete, - test=test, - nameservers=ns, - dns_timeout=dt) - callback(res) - server.idle() - except ConnectionAbortedError: - raise IMAPError("Connection aborted") - except TimeoutError: - raise IMAPError("Connection timed out") - except SSLError as error: - raise IMAPError("SSL error: {0}".format(error.__str__())) - except CertificateError as error: - raise IMAPError("Certificate error: {0}".format(error.__str__())) - except BrokenPipeError: - logger.debug("IMAP error: Broken pipe") - logger.debug("Reconnecting watcher") - try: - server.shutdown() - except Exception as e: - logger.debug("Failed to disconnect: {0}".format(e.__str__())) - server = imapclient.IMAPClient(host) - server.login(username, password) - server.select_folder(rf) - idle_start_time = time.monotonic() - ms = "MOVE" in get_imap_capabilities(server) - res = get_dmarc_reports_from_inbox(connection=server, - move_supported=ms, - reports_folder=rf, - archive_folder=af, - delete=delete, - test=test, - nameservers=ns, - dns_timeout=dt) - callback(res) - server.idle() - - while True: - try: - # Refresh the IDLE session every 5 minutes to stay connected - if time.monotonic() - idle_start_time > 5 * 60: - logger.debug("IMAP: Refreshing IDLE session") - server.idle_done() - server.idle() - idle_start_time = time.monotonic() - responses = server.idle_check(timeout=wait) - if responses is not None: - if len(responses) == 0: - # Gmail/G-Suite does not generate anything in the responses - server.idle_done() - res = get_dmarc_reports_from_inbox(connection=server, - move_supported=ms, - reports_folder=rf, - archive_folder=af, - delete=delete, - test=test, - nameservers=ns, - dns_timeout=dt) - callback(res) - server.idle() - idle_start_time = time.monotonic() - for response in responses: - logging.debug("Received response: {0}".format(response)) - if response[0] != 0 and response[1] == b'RECENT': - server.idle_done() - res = get_dmarc_reports_from_inbox(connection=server, - move_supported=ms, - reports_folder=rf, - archive_folder=af, - delete=delete, - test=test, - nameservers=ns, - dns_timeout=dt) - callback(res) - server.idle() - idle_start_time = time.monotonic() - break - except imapclient.exceptions.IMAPClientError as error: - error = error.__str__().replace("b'", "").replace("'", "") - # Workaround for random Exchange/Office365 IMAP errors - if "unexpected response" in error or "BAD" in error: - sleep_minutes = 5 - logger.debug( - "{0}. " - "Waiting {1} minutes before trying again".format( - error, - sleep_minutes)) - logger.debug("Reconnecting watcher") - try: - server.logout() - except Exception as e: - logger.debug("Failed to disconnect: {0}".format( - e.__str__())) - server = imapclient.IMAPClient(host) - server.login(username, password) - server.select_folder(rf) - idle_start_time = time.monotonic() - ms = "MOVE" in get_imap_capabilities(server) - res = get_dmarc_reports_from_inbox(connection=server, - move_supported=ms, - reports_folder=rf, - archive_folder=af, - delete=delete, - test=test, - nameservers=ns, - dns_timeout=dt) - callback(res) - server.idle() - else: - raise IMAPError(error) - except socket.gaierror: - raise IMAPError("DNS resolution failed") - except ConnectionRefusedError: - raise IMAPError("Connection refused") - except (KeyError, socket.error, BrokenPipeError, ConnectionResetError): - logger.debug("IMAP error: Connection reset") - logger.debug("Reconnecting watcher") - try: - server.logout() - except Exception as e: - logger.debug("Failed to disconnect: {0}".format(e.__str__())) - server = imapclient.IMAPClient(host) - server.login(username, password) - server.select_folder(rf) - idle_start_time = time.monotonic() - ms = "MOVE" in get_imap_capabilities(server) - res = get_dmarc_reports_from_inbox(connection=server, - move_supported=ms, - reports_folder=rf, - archive_folder=af, - delete=delete, - test=test, - nameservers=ns, - dns_timeout=dt) - callback(res) - server.idle() - except KeyError: - logger.debug("IMAP error: Server returned unexpected result") - logger.debug("Reconnecting watcher") - try: - server.logout() - except Exception as e: - logger.debug("Failed to log out: {0}".format(e.__str__())) - server = imapclient.IMAPClient(host) - server.login(username, password) - server.select_folder(rf) - idle_start_time = time.monotonic() - ms = "MOVE" in get_imap_capabilities(server) - res = get_dmarc_reports_from_inbox(connection=server, - move_supported=ms, - reports_folder=rf, - archive_folder=af, - delete=delete, - test=test, - nameservers=ns, - dns_timeout=dt) - callback(res) - server.idle() - except ConnectionAbortedError: - raise IMAPError("Connection aborted") - except TimeoutError: - raise IMAPError("Connection timed out") - except SSLError as error: - raise IMAPError("SSL error: {0}".format(error.__str__())) - except CertificateError as error: - raise IMAPError("Certificate error: {0}".format(error.__str__())) - except BrokenPipeError: - logger.debug("IMAP error: Broken pipe") - logger.debug("Reconnecting watcher") - try: - server.shutdown() - except Exception as e: - logger.debug("Failed to disconnect: {0}".format(e.__str__())) - server = imapclient.IMAPClient(host) - server.login(username, password) - server.select_folder(rf) - idle_start_time = time.monotonic() - res = get_dmarc_reports_from_inbox(connection=server, - move_supported=ms, - reports_folder=rf, - archive_folder=af, - delete=delete, - test=test, - nameservers=ns, - dns_timeout=dt) - callback(res) - server.idle() - except KeyboardInterrupt: - break - - try: - server.idle_done() - except BrokenPipeError: - pass
+ send_email(host, mail_from, mail_to, message_cc=mail_cc, + message_bcc=mail_bcc, port=port, + require_encryption=require_encryption, verify=verify, + username=username, password=password, subject=subject, + attachments=attachments, plain_message=message)
diff --git a/_modules/parsedmarc/elastic.html b/_modules/parsedmarc/elastic.html index 328dd0b..f49f4aa 100644 --- a/_modules/parsedmarc/elastic.html +++ b/_modules/parsedmarc/elastic.html @@ -8,7 +8,7 @@ - parsedmarc.elastic — parsedmarc 6.4.2 documentation + parsedmarc.elastic — parsedmarc 6.5.0 documentation @@ -58,7 +58,7 @@
- 6.4.2 + 6.5.0
diff --git a/_modules/parsedmarc/splunk.html b/_modules/parsedmarc/splunk.html index db743f1..7c33b97 100644 --- a/_modules/parsedmarc/splunk.html +++ b/_modules/parsedmarc/splunk.html @@ -8,7 +8,7 @@ - parsedmarc.splunk — parsedmarc 6.4.2 documentation + parsedmarc.splunk — parsedmarc 6.5.0 documentation @@ -58,7 +58,7 @@
- 6.4.2 + 6.5.0
diff --git a/_modules/parsedmarc/utils.html b/_modules/parsedmarc/utils.html index 0cf0958..927dd90 100644 --- a/_modules/parsedmarc/utils.html +++ b/_modules/parsedmarc/utils.html @@ -8,7 +8,7 @@ - parsedmarc.utils — parsedmarc 6.4.2 documentation + parsedmarc.utils — parsedmarc 6.5.0 documentation @@ -58,7 +58,7 @@
- 6.4.2 + 6.5.0
@@ -304,7 +304,7 @@ if record_type == "TXT": resource_records = list(map( lambda r: r.strings, - resolver.query(domain, record_type, tcp=True))) + resolver.query(domain, record_type, lifetime=timeout))) _resource_record = [ resource_record[0][:0].join(resource_record) for resource_record in resource_records if resource_record] @@ -312,7 +312,7 @@ else: records = list(map( lambda r: r.to_text().replace('"', '').rstrip("."), - resolver.query(domain, record_type, tcp=True))) + resolver.query(domain, record_type, lifetime=timeout))) if cache: cache[cache_key] = records @@ -406,7 +406,7 @@ return human_timestamp_to_datetime(human_timestamp).timestamp()
-
[docs]def get_ip_address_country(ip_address, parallel=False): +
[docs]def get_ip_address_country(ip_address, parallel=False, offline=False): """ Uses the MaxMind Geolite2 Country database to return the ISO code for the country associated with the given IPv4 or IPv6 address @@ -414,6 +414,7 @@ Args: ip_address (str): The IP address to query for parallel (bool): Parallel processing + offline (bool): Do not make online queries for geolocation and DNS Returns: str: And ISO country code associated with the given IP address @@ -424,7 +425,7 @@ Args: location (str): Local location for the database file """ - if parallel: + if parallel or offline: logging.warning("GeoLite2-Country.mmdb is missing." "please install and run geoipupdate as root to " "get the latest version.") @@ -489,14 +490,15 @@ return country
-
[docs]def get_ip_address_info(ip_address, cache=None, nameservers=None, - timeout=2.0, parallel=False): +
[docs]def get_ip_address_info(ip_address, cache=None, offline=False, + nameservers=None, timeout=2.0, parallel=False): """ Returns reverse DNS and country information for the given IP address Args: ip_address (str): The IP address to check cache (ExpiringDict): Cache storage + offline (bool): Do not make online queries for geolocation or DNS nameservers (list): A list of one or more nameservers to use (Cloudflare's public DNS resolvers by default) timeout (float): Sets the DNS timeout in seconds @@ -513,9 +515,12 @@ return info info = OrderedDict() info["ip_address"] = ip_address - reverse_dns = get_reverse_dns(ip_address, - nameservers=nameservers, - timeout=timeout) + if offline: + reverse_dns = None + else: + reverse_dns = get_reverse_dns(ip_address, + nameservers=nameservers, + timeout=timeout) country = get_ip_address_country(ip_address, parallel=parallel) info["country"] = country info["reverse_dns"] = reverse_dns diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt index a34b030..032960e 100644 --- a/_sources/index.rst.txt +++ b/_sources/index.rst.txt @@ -63,9 +63,10 @@ CLI help :: usage: parsedmarc [-h] [-c CONFIG_FILE] [--strip-attachment-payloads] - [-o OUTPUT] [-n NAMESERVERS [NAMESERVERS ...]] - [-t DNS_TIMEOUT] [-s] [--debug] [--log-file LOG_FILE] [-v] - [file_path [file_path ...]] + [-o OUTPUT] [-n NAMESERVERS [NAMESERVERS ...]] + [-t DNS_TIMEOUT] [--offline] [-s] [--debug] + [--log-file LOG_FILE] [-v] + [file_path [file_path ...]] Parses DMARC reports @@ -86,12 +87,14 @@ CLI help nameservers) -t DNS_TIMEOUT, --dns_timeout DNS_TIMEOUT number of seconds to wait for an answer from DNS - (default: 6.0) + (default: 2.0) + --offline Do not make online queries for geolocation or DNS -s, --silent only print errors and warnings --debug print debugging information --log-file LOG_FILE output logging to a file -v, --version show program's version number and exit + .. note:: In ``parsedmarc`` 6.0.0, most CLI options were moved to a configuration file, described below. @@ -137,6 +140,7 @@ The full set of configuration options are: - ``save_forensic`` - bool: Save forensic report data to the Elasticsearch and/or Splunk - ``strip_attachment_payloads`` - bool: Remove attachment payloads from results - ``output`` - str: Directory to place JSON and CSV files in + - ``offline`` - bool: Do not use online queries for geolocation or DNS - ``nameservers`` - str: A comma separated list of DNS resolvers (Default: `Cloudflare's public resolvers`_) - ``dns_timeout`` - float: DNS timeout period - ``debug`` - bool: Print debugging messages @@ -1482,10 +1486,6 @@ parsedmarc.elastic parsedmarc.splunk ----------------- -.. toctree:: - :maxdepth: 2 - :caption: Contents: - .. automodule:: parsedmarc.splunk :members: diff --git a/_static/documentation_options.js b/_static/documentation_options.js index a231b66..6ccafe5 100644 --- a/_static/documentation_options.js +++ b/_static/documentation_options.js @@ -1,6 +1,6 @@ var DOCUMENTATION_OPTIONS = { URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '6.4.2', + VERSION: '6.5.0', LANGUAGE: 'None', COLLAPSE_INDEX: false, FILE_SUFFIX: '.html', diff --git a/genindex.html b/genindex.html index e0bce44..dcfd4b9 100644 --- a/genindex.html +++ b/genindex.html @@ -9,7 +9,7 @@ - Index — parsedmarc 6.4.2 documentation + Index — parsedmarc 6.5.0 documentation @@ -59,7 +59,7 @@
- 6.4.2 + 6.5.0
@@ -253,14 +253,12 @@

I

@@ -1699,24 +1690,23 @@ or bytes.

-parsedmarc.get_dmarc_reports_from_inbox(host=None, user=None, password=None, connection=None, port=None, ssl=True, ssl_context=None, move_supported=None, reports_folder='INBOX', archive_folder='Archive', delete=False, test=False, nameservers=None, dns_timeout=6.0, strip_attachment_payloads=False, results=None)[source]
-

Fetches and parses DMARC reports from sn inbox

+parsedmarc.get_dmarc_reports_from_inbox(connection=None, host=None, user=None, password=None, port=None, ssl=True, verify=True, reports_folder='INBOX', archive_folder='Archive', delete=False, test=False, offline=False, nameservers=None, dns_timeout=6.0, strip_attachment_payloads=False, results=None)[source] +

Fetches and parses DMARC reports from an inbox

Parameters
    +
  • connection – An IMAPClient connection to reuse

  • host – The mail server hostname or IP address

  • user – The mail server user

  • password – The mail server password

  • -
  • connection – An IMAPCLient connection to reuse

  • port – The mail server port

  • ssl (bool) – Use SSL/TLS

  • -
  • ssl_context (SSLContext) – A SSL context

  • -
  • move_supported – Indicate if the IMAP server supports the MOVE command

  • -
  • if None) ((autodetect) –

  • +
  • verify (bool) – Verify SSL/TLS certificate

  • reports_folder – The IMAP folder where reports can be found

  • archive_folder – The folder to move processed mail to

  • delete (bool) – Delete messages after processing them

  • test (bool) – Do not move or delete messages after processing them

  • +
  • offline (bool) – Do not query onfline for geolocation or DNS

  • nameservers (list) – A list of DNS nameservers to query

  • dns_timeout (float) – Set the DNS query timeout

  • strip_attachment_payloads (bool) – Remove attachment payloads from

  • @@ -1764,13 +1754,14 @@ or bytes.

    -parsedmarc.parse_aggregate_report_file(_input, nameservers=None, dns_timeout=2.0, parallel=False)[source]
    +parsedmarc.parse_aggregate_report_file(_input, offline=False, nameservers=None, dns_timeout=2.0, parallel=False)[source]

    Parses a file at the given path, a file-like object. or bytes as a aggregate DMARC report

    Parameters
    • _input – A path to a file, a file like object, or bytes

    • +
    • offline (bool) – Do not query online for geolocation or DNS

    • nameservers (list) – A list of one or more nameservers to use

    • public DNS resolvers by default) ((Cloudflare's) –

    • dns_timeout (float) – Sets the DNS timeout in seconds

    • @@ -1788,12 +1779,13 @@ aggregate DMARC report

      -parsedmarc.parse_aggregate_report_xml(xml, nameservers=None, timeout=2.0, parallel=False)[source]
      +parsedmarc.parse_aggregate_report_xml(xml, offline=False, nameservers=None, timeout=2.0, parallel=False)[source]

      Parses a DMARC XML report string and returns a consistent OrderedDict

      Parameters
      • xml (str) – A string of DMARC aggregate report XML

      • +
      • offline (bool) – Do not query online for geolocation or DNS

      • nameservers (list) – A list of one or more nameservers to use

      • public DNS resolvers by default) ((Cloudflare's) –

      • timeout (float) – Sets the DNS timeout in seconds

      • @@ -1811,12 +1803,13 @@ aggregate DMARC report

        -parsedmarc.parse_forensic_report(feedback_report, sample, msg_date, nameservers=None, dns_timeout=2.0, strip_attachment_payloads=False, parallel=False)[source]
        +parsedmarc.parse_forensic_report(feedback_report, sample, msg_date, offline=False, nameservers=None, dns_timeout=2.0, strip_attachment_payloads=False, parallel=False)[source]

        Converts a DMARC forensic report and sample to a OrderedDict

        Parameters
        • feedback_report (str) – A message’s feedback report as a string

        • +
        • offline (bool) – Do not query online for geolocation or DNS

        • sample (str) – The RFC 822 headers or RFC 822 message sample

        • msg_date (str) – The message’s date header

        • nameservers (list) – A list of one or more nameservers to use

        • @@ -1838,12 +1831,13 @@ aggregate DMARC report

          -parsedmarc.parse_report_email(input_, nameservers=None, dns_timeout=2.0, strip_attachment_payloads=False, parallel=False)[source]
          +parsedmarc.parse_report_email(input_, offline=False, nameservers=None, dns_timeout=2.0, strip_attachment_payloads=False, parallel=False)[source]

          Parses a DMARC report from an email

          Parameters
          • input_ – An emailed DMARC report in RFC 822 format, as bytes or a string

          • +
          • offline (bool) – Do not query online for geolocation on DNS

          • nameservers (list) – A list of one or more nameservers to use

          • dns_timeout (float) – Sets the DNS timeout in seconds

          • strip_attachment_payloads (bool) – Remove attachment payloads from

          • @@ -1866,7 +1860,7 @@ aggregate DMARC report

            -parsedmarc.parse_report_file(input_, nameservers=None, dns_timeout=2.0, strip_attachment_payloads=False, parallel=False)[source]
            +parsedmarc.parse_report_file(input_, nameservers=None, dns_timeout=2.0, strip_attachment_payloads=False, offline=False, parallel=False)[source]

            Parses a DMARC aggregate or forensic file at the given path, a file-like object. or bytes

            @@ -1878,6 +1872,7 @@ file-like object. or bytes

          • dns_timeout (float) – Sets the DNS timeout in seconds

          • strip_attachment_payloads (bool) – Remove attachment payloads from

          • report results (forensic) –

          • +
          • offline (bool) – Do not make online queries for geolocation or DNS

          • parallel (bool) – Parallel processing

          @@ -1942,32 +1937,36 @@ headers

          -parsedmarc.watch_inbox(host, username, password, callback, port=None, ssl=True, ssl_context=None, reports_folder='INBOX', archive_folder='Archive', delete=False, test=False, wait=30, nameservers=None, dns_timeout=6.0, strip_attachment_payloads=False)[source]
          +parsedmarc.watch_inbox(host, username, password, callback, port=None, ssl=True, verify=True, reports_folder='INBOX', archive_folder='Archive', delete=False, test=False, idle_timeout=30, offline=False, nameservers=None, dns_timeout=6.0, strip_attachment_payloads=False)[source]

          Use an IDLE IMAP connection to parse incoming emails, and pass the results -to a callback function

          -
          -
          Parameters
          -
            -
          • host – The mail server hostname or IP address

          • -
          • username – The mail server username

          • -
          • password – The mail server password

          • -
          • callback – The callback function to receive the parsing results

          • -
          • port – The mail server port

          • -
          • ssl (bool) – Use SSL/TLS

          • -
          • ssl_context (SSLContext) – A SSL context

          • -
          • reports_folder – The IMAP folder where reports can be found

          • -
          • archive_folder – The folder to move processed mail to

          • -
          • delete (bool) – Delete messages after processing them

          • -
          • test (bool) – Do not move or delete messages after processing them

          • -
          • wait (int) – Number of seconds to wait for a IMAP IDLE response

          • -
          • nameservers (list) – A list of one or more nameservers to use

          • -
          • public DNS resolvers by default) ((Cloudflare's) –

          • -
          • dns_timeout (float) – Set the DNS query timeout

          • -
          • strip_attachment_payloads (bool) – Replace attachment payloads in

          • -
          • report samples with None (forensic) –

          • -
          -
          -
          +to a callback function +:param host: The mail server hostname or IP address +:param username: The mail server username +:param password: The mail server password +:param callback: The callback function to receive the parsing results +:param port: The mail server port +:param ssl: Use SSL/TLS +:type ssl: bool +:param verify: Verify the TLS/SSL certificate +:type verify: bool +:param reports_folder: The IMAP folder where reports can be found +:param archive_folder: The folder to move processed mail to +:param delete: Delete messages after processing them +:type delete: bool +:param test: Do not move or delete messages after processing them +:type test: bool +:param idle_timeout: Number of seconds to wait for a IMAP IDLE response +:type idle_timeout: int +:param offline: Do not query online for geolocation or DNS +:type offline: bool +:param nameservers: A list of one or more nameservers to use +:type nameservers: list +:param (Cloudflare’s public DNS resolvers by default): +:param dns_timeout: Set the DNS query timeout +:type dns_timeout: float +:param strip_attachment_payloads: Replace attachment payloads in +:type strip_attachment_payloads: bool +:param forensic report samples with None:

          @@ -2072,11 +2071,9 @@ index

          -
          -

          parsedmarc.splunk

          -
          -
          -
          +
          +

          parsedmarc.splunk

          +
          class parsedmarc.splunk.HECClient(url, access_token, index, source='parsedmarc', verify=True, timeout=60)[source]

          A client for a Splunk HTTP Events Collector (HEC)

          @@ -2209,7 +2206,7 @@ standard RFC 822 format

          -parsedmarc.utils.get_ip_address_country(ip_address, parallel=False)[source]
          +parsedmarc.utils.get_ip_address_country(ip_address, parallel=False, offline=False)[source]

          Uses the MaxMind Geolite2 Country database to return the ISO code for the country associated with the given IPv4 or IPv6 address

          @@ -2217,6 +2214,7 @@ country associated with the given IPv4 or IPv6 address

          • ip_address (str) – The IP address to query for

          • parallel (bool) – Parallel processing

          • +
          • offline (bool) – Do not make online queries for geolocation and DNS

          Returns
          @@ -2230,13 +2228,14 @@ country associated with the given IPv4 or IPv6 address

          -parsedmarc.utils.get_ip_address_info(ip_address, cache=None, nameservers=None, timeout=2.0, parallel=False)[source]
          +parsedmarc.utils.get_ip_address_info(ip_address, cache=None, offline=False, nameservers=None, timeout=2.0, parallel=False)[source]

          Returns reverse DNS and country information for the given IP address

          Parameters
          • ip_address (str) – The IP address to check

          • cache (ExpiringDict) – Cache storage

          • +
          • offline (bool) – Do not make online queries for geolocation or DNS

          • nameservers (list) – A list of one or more nameservers to use

          • public DNS resolvers by default) ((Cloudflare's) –

          • timeout (float) – Sets the DNS timeout in seconds

          • diff --git a/objects.inv b/objects.inv index 493dcfd..30aa5b3 100644 --- a/objects.inv +++ b/objects.inv @@ -1,6 +1,5 @@ # Sphinx inventory version 2 # Project: parsedmarc -# Version: 6.4.2 +# Version: 6.5.0 # The remainder of this file is compressed using zlib. -xڭn0~ -B=f$ crq<}(D93$ #WKexH~9]P['}1nWse  mFS= _ޣ5.4׫D8^V.]cDV PװG[ir7mK H!ofq%zwSˋ4Mu!e uX%G3}Z[ zuF}٘CP`) !E {!OŽc lE:Jgj$JFzp[v}5ϕU]2Йl7oemͳ2Օ3Oagr9Ev]{{ B6ZSu\gF1TAҘ|?Gf8 x+@磫A!M? O)3Qwy:`y|F)Ϩڡۺz%Et 9(-Ƽ; _Jؠ$ <[m^͸a3I7J]9cQocHW̠AХ'{cVH>Y=ΟoTچ7Dzz. \ No newline at end of file +xڭWn0+W PhA19p+ח8EY83-8\cQ"AxvAoU6N3=H}ﰇh  mFSr"q`t+B >$ n!?adOIvǒiQDۨhS^jc4Meu!}e @JɷtJ1&R6B 4T? ;Vk`+R+]ђJfуٲӠQOa\[y>LS`y+~lY-R.XjQ?)A8agsB.-ݘ'- )UIGh3Z U4*ߏ.tlᕁέA!M? O𔙨;^F"L`p6#CF.*4>yj,J N趩^"~EqT&xvc="!>k d~E^EMN4,14E؛5&:% ]Zp>zv#{|&d w*zZJ \ No newline at end of file diff --git a/py-modindex.html b/py-modindex.html index 896c72f..0c28667 100644 --- a/py-modindex.html +++ b/py-modindex.html @@ -8,7 +8,7 @@ - Python Module Index — parsedmarc 6.4.2 documentation + Python Module Index — parsedmarc 6.5.0 documentation @@ -61,7 +61,7 @@
            - 6.4.2 + 6.5.0
            diff --git a/search.html b/search.html index 4cd5ca6..e751bd8 100644 --- a/search.html +++ b/search.html @@ -8,7 +8,7 @@ - Search — parsedmarc 6.4.2 documentation + Search — parsedmarc 6.5.0 documentation @@ -59,7 +59,7 @@
            - 6.4.2 + 6.5.0
            diff --git a/searchindex.js b/searchindex.js index 87dcbb3..8b344d7 100644 --- a/searchindex.js +++ b/searchindex.js @@ -1 +1 @@ -Search.setIndex({docnames:["index"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.todo":1,"sphinx.ext.viewcode":1,sphinx:56},filenames:["index.rst"],objects:{"":{parsedmarc:[0,0,0,"-"]},"parsedmarc.elastic":{AlreadySaved:[0,1,1,""],ElasticsearchError:[0,1,1,""],create_indexes:[0,2,1,""],migrate_indexes:[0,2,1,""],save_aggregate_report_to_elasticsearch:[0,2,1,""],save_forensic_report_to_elasticsearch:[0,2,1,""],set_hosts:[0,2,1,""]},"parsedmarc.splunk":{HECClient:[0,3,1,""],SplunkError:[0,1,1,""]},"parsedmarc.splunk.HECClient":{save_aggregate_reports_to_splunk:[0,4,1,""],save_forensic_reports_to_splunk:[0,4,1,""]},"parsedmarc.utils":{DownloadError:[0,1,1,""],EmailParserError:[0,1,1,""],convert_outlook_msg:[0,2,1,""],decode_base64:[0,2,1,""],get_base_domain:[0,2,1,""],get_filename_safe_string:[0,2,1,""],get_ip_address_country:[0,2,1,""],get_ip_address_info:[0,2,1,""],get_reverse_dns:[0,2,1,""],human_timestamp_to_datetime:[0,2,1,""],human_timestamp_to_timestamp:[0,2,1,""],is_outlook_msg:[0,2,1,""],parse_email:[0,2,1,""],query_dns:[0,2,1,""],timestamp_to_datetime:[0,2,1,""],timestamp_to_human:[0,2,1,""]},parsedmarc:{IMAPError:[0,1,1,""],InvalidAggregateReport:[0,1,1,""],InvalidDMARCReport:[0,1,1,""],InvalidForensicReport:[0,1,1,""],ParserError:[0,1,1,""],SMTPError:[0,1,1,""],elastic:[0,0,0,"-"],email_results:[0,2,1,""],extract_xml:[0,2,1,""],get_dmarc_reports_from_inbox:[0,2,1,""],get_imap_capabilities:[0,2,1,""],get_report_zip:[0,2,1,""],parse_aggregate_report_file:[0,2,1,""],parse_aggregate_report_xml:[0,2,1,""],parse_forensic_report:[0,2,1,""],parse_report_email:[0,2,1,""],parse_report_file:[0,2,1,""],parsed_aggregate_reports_to_csv:[0,2,1,""],parsed_forensic_reports_to_csv:[0,2,1,""],save_output:[0,2,1,""],splunk:[0,0,0,"-"],utils:[0,0,0,"-"],watch_inbox:[0,2,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","exception","Python exception"],"2":["py","function","Python function"],"3":["py","class","Python class"],"4":["py","method","Python method"]},objtypes:{"0":"py:module","1":"py:exception","2":"py:function","3":"py:class","4":"py:method"},terms:{"2017a":0,"50m":0,"\u00fcbersicht":0,"break":0,"byte":0,"case":0,"class":0,"default":0,"float":0,"function":0,"import":0,"int":0,"long":0,"new":0,"null":0,"public":0,"return":0,"switch":0,"true":0,"var":0,"while":0,And:0,DNS:0,For:0,OLE:0,TLS:0,That:0,The:0,Then:0,These:0,Use:0,Uses:0,With:0,Yes:0,_input:0,abl:0,abov:0,accept:0,access_token:0,accident:0,account:0,acm:0,across:0,action:0,actual:0,add:0,add_head:0,added:0,adding:0,addit:0,address:0,addresse:0,adkim:0,admin:0,administr:0,adsl:0,aes128:0,aes256:0,after:0,against:0,agari:0,age:0,aggregate_index:0,aggregate_report:0,aggregate_top:0,all:0,allow:0,allowremot:0,alreadysav:0,also:0,alter:0,altern:0,although:0,alwai:0,ani:0,anonym:0,anoth:0,answer:0,apach:0,apache2:0,appear:0,appendix:0,appli:0,approach:0,approxim:0,apt:0,archiv:0,archive_fold:0,argument:0,arriv:0,arrival_d:0,arrival_date_utc:0,artifact:0,ask:0,asmx:0,aspf:0,assign:0,associ:0,attach:0,attachment_filenam:0,auth:0,auth_bas:0,auth_basic_user_fil:0,auth_failur:0,auth_result:0,authent:0,authentication_mechan:0,authentication_result:0,auto:0,autodetect:0,avail:0,avoid:0,b2c:0,base64:0,base:0,base_domain:0,basic:0,bcc:0,bd6e1bb5:0,becaus:0,been:0,begin_d:0,behind:0,being:0,bellsouth:0,below:0,between:0,bin:0,binari:0,bind:0,bindaddress:0,bitbucket:0,blank:0,block:0,bodi:0,bool:0,brand:0,busi:0,button:0,bz2:0,cach:0,call:0,callback:0,came:0,can:0,capabl:0,caus:0,center:0,cento:0,cert:0,cert_path:0,certif:0,cest:0,chacha20:0,chain:0,chang:0,charact:0,charset:0,chart:0,check:0,checkbox:0,checkdmarc:0,chines:0,chmod:0,choos:0,chown:0,chunk_siz:0,cisco:0,click:0,client:0,clientsotimeout:0,cloudflar:0,code:0,collect:0,collector:0,com:0,come:0,comma:0,command:0,comment:0,commerci:0,common:0,commun:0,complet:0,compli:0,compliant:0,compress:0,config:0,config_fil:0,conform:0,connect:0,consid:0,consist:0,consolid:0,consum:0,contact:0,contain:0,content:0,context:0,control:0,convert:0,convert_outlook_msg:0,copi:0,core:0,correctli:0,could:0,count:0,countri:0,crash:0,creat:0,create_index:0,credenti:0,crt:0,csr:0,cumul:0,current:0,custom:0,daemon:0,dai:0,daili:0,dat:0,data:0,databas:0,date:0,date_utc:0,datetim:0,deb:0,debian:0,debug:0,decod:0,decode_base64:0,defens:0,delai:0,delet:0,delivery_result:0,demystifi:0,deploi:0,describ:0,descript:0,detail:0,develop:0,dict:0,dictionari:0,differ:0,digest:0,directli:0,directori:0,dis:0,disabl:0,disclaim:0,displai:0,display_nam:0,disposit:0,dkim_align:0,dkim_domain:0,dkim_result:0,dkim_selector:0,dkm:0,dmarc_aggreg:0,dmarc_forens:0,dmarc_moderation_act:0,dmarc_none_moderation_act:0,dmarc_quarentine_moderation_act:0,dmarcian:0,dmarcresport:0,dns_timeout:0,doctyp:0,doe:0,domainawar:0,don:0,down:0,download:0,downloaderror:0,draft:0,dtd:0,dure:0,each:0,earlier:0,easi:0,easier:0,easy_instal:0,ecdh:0,ecdsa:0,echo:0,edit:0,editor:0,effici:0,elasticsearcherror:0,els:0,email:0,email_result:0,emailparsererror:0,empti:0,enabl:0,enableew:0,enablekeepal:0,enableproxi:0,encod:0,encount:0,encrypt:0,end:0,end_dat:0,enforc:0,ensur:0,entir:0,envelop:0,envelope_from:0,envelope_to:0,environ:0,error:0,especi:0,etc:0,even:0,event:0,everi:0,exactli:0,exampl:0,exampleus:0,except:0,exchang:0,exclud:0,execstart:0,exist:0,exit:0,expiringdict:0,explain:0,explicit:0,extract:0,extract_xml:0,eyes:0,factor:0,fail:0,failur:0,fals:0,fantast:0,faster:0,feedback:0,feedback_report:0,feedback_typ:0,fetch:0,few:0,field:0,file_path:0,filenam:0,filename_safe_subject:0,fill:0,filter:0,financ:0,find:0,fine:0,first:0,first_strip_reply_to:0,fit:0,fix:0,flag:0,flat:0,flexibl:0,folder:0,foldersizelimit:0,follow:0,footer:0,fore:0,forensic_index:0,forensic_report:0,forensic_top:0,format:0,forward:0,found:0,foundat:0,fqdn:0,frame:0,fraud:0,free:0,fresh:0,friendli:0,from:0,from_is_list:0,ftp_proxi:0,full:0,fulli:0,further:0,gatewai:0,gcm:0,gdpr:0,gener:0,geoip:0,geoipupd:0,geolite2:0,get:0,get_base_domain:0,get_dmarc_reports_from_inbox:0,get_filename_safe_str:0,get_imap_cap:0,get_ip_address_countri:0,get_ip_address_info:0,get_report_zip:0,get_reverse_dn:0,git:0,github:0,give:0,given:0,glass:0,global:0,gmail:0,goe:0,googl:0,gpg:0,graph:0,group:0,gzip:0,hand:0,handl:0,has:0,has_defect:0,have:0,head:0,header:0,header_from:0,headless:0,healthcar:0,heap:0,heavi:0,hec:0,hecclient:0,hectokengoesher:0,here:0,high:0,higher:0,highli:0,his:0,hop:0,host:0,hostnam:0,hover:0,href:0,html:0,htpasswd:0,http2:0,http:0,http_proxi:0,httpasswd:0,httpd:0,https_proxi:0,human:0,human_timestamp:0,human_timestamp_to_datetim:0,human_timestamp_to_timestamp:0,icon:0,ideal:0,ident:0,identifi:0,idl:0,imap:0,imapalwaysapproxmsgs:0,imapautoexpung:0,imapcli:0,imaperror:0,imapidledelai:0,imapport:0,immedi:0,impli:0,improv:0,includ:0,include_list_post_head:0,include_rfc2369_head:0,include_sender_head:0,includesubdomain:0,incom:0,increas:0,index_suffix:0,industri:0,inform:0,ini:0,input_:0,insid:0,instanc:0,instead:0,intend:0,interact:0,interakt:0,interfer:0,invalid:0,invalidaggregatereport:0,invaliddmarcreport:0,invalidforensicreport:0,ip_address:0,ipv4:0,ipv6:0,is_outlook_msg:0,iso:0,issu:0,its:0,java:0,job:0,joe:0,journalctl:0,jre:0,just:0,jvm:0,jxf:0,kafka:0,kb4099855:0,kb4134118:0,kb4295699:0,keepal:0,kei:0,keyout:0,kibana_saved_object:0,kind:0,know:0,known:0,languag:0,larg:0,larger:0,later:0,latest:0,layout:0,leak:0,least:0,leav:0,left:0,legal:0,legitim:0,level:0,libemail:0,like:0,limit:0,line:0,link:0,linux:0,linux_x86_64:0,listen:0,load:0,local:0,localhost:0,locat:0,log:0,log_fil:0,login:0,longer:0,look:0,loopback:0,lot:0,lua:0,maco:0,magnifi:0,mai:0,mail_from:0,mail_to:0,mailbox:0,mailer:0,mailrelai:0,mailto:0,main:0,make:0,malici:0,manag:0,manual:0,map:0,market:0,match:0,max:0,maximum:0,maxmind:0,mechan:0,member:0,mention:0,menu:0,messag:0,message_id:0,meta:0,mfrom:0,microsoft:0,might:0,migrate_index:0,mime:0,minimum:0,minut:0,mitig:0,mkdir:0,mmdb:0,mobil:0,mode:0,modern:0,modifi:0,modul:0,mon:0,monitor:0,monthli:0,monthly_index:0,more:0,most:0,mous:0,move:0,move_support:0,msg:0,msg_byte:0,msg_date:0,msg_footer:0,msg_header:0,msgconvert:0,much:0,multi:0,mung:0,must:0,n_proc:0,name:0,nameserv:0,nano:0,navig:0,ncontent:0,ndate:0,need:0,neeed:0,nelson:0,net:0,network:0,newest:0,newkei:0,next:0,nfrom:0,nginx:0,nmessag:0,nmime:0,node:0,non:0,none:0,noproxyfor:0,norepli:0,normal:0,nosecureimap:0,nosniff:0,notabl:0,now:0,nsubject:0,nto:0,number:0,number_of_replica:0,number_of_shard:0,nwettbewerb:0,object:0,observ:0,occur:0,occurr:0,oct:0,off:0,office365:0,often:0,old:0,older:0,oldest:0,ondmarc:0,one:0,onli:0,onlin:0,opendn:0,openssl:0,opt:0,ordereddict:0,org:0,org_email:0,org_extra_contact_info:0,org_nam:0,organ:0,organis:0,origin:0,original_envelope_id:0,original_mail_from:0,original_rcpt_to:0,other:0,our:0,out:0,outdat:0,outgo:0,outlook:0,output_directori:0,outsid:0,over:0,overrid:0,overwrit:0,own:0,pack:0,packag:0,pad:0,page:0,pan:0,parallel:0,param:0,paramet:0,parent:0,pars:0,parse_aggregate_report_fil:0,parse_aggregate_report_xml:0,parse_email:0,parse_forensic_report:0,parse_report_email:0,parse_report_fil:0,parsed_aggregate_reports_to_csv:0,parsed_forensic_reports_to_csv:0,parsed_sampl:0,parser:0,parsererror:0,part:0,particular:0,particularli:0,pass:0,passag:0,passsword:0,password:0,past:0,patch:0,path:0,payload:0,pct:0,percentag:0,perform:0,period:0,perl:0,permiss:0,peter:0,pie:0,pip3:0,pip:0,place:0,plain:0,plaintext:0,platform:0,pleas:0,plu:0,polici:0,policy_evalu:0,policy_override_com:0,policy_override_reason:0,policy_publish:0,poll:0,poly1305:0,port:0,portabl:0,posit:0,possibl:0,post:0,poster:0,postoriu:0,prefix:0,preload:0,premad:0,previou:0,previous:0,print:0,printabl:0,privaci:0,process:0,produc:0,product:0,program:0,project:0,prompt:0,proofpoint:0,properti:0,protect:0,provid:0,prox:0,proxi:0,proxy_add_x_forwarded_for:0,proxy_pass:0,proxy_set_head:0,proxyhost:0,proxypassword:0,proxyport:0,proxyus:0,pry:0,public_suffix_list:0,publicsuffix:0,publish:0,pypi:0,python34:0,python3:0,python:0,quarantin:0,queri:0,query_dn:0,quot:0,rais:0,ram:0,rasi:0,rather:0,readabl:0,readonlyrest:0,real:0,realli:0,reason:0,receiv:0,recipi:0,recogn:0,recommend:0,record_typ:0,refer:0,regardless:0,regul:0,regular:0,reject:0,relai:0,relat:0,releas:0,reli:0,reliabl:0,reload:0,remain:0,remot:0,remote_addr:0,remov:0,repeat:0,replac:0,repli:0,replica:0,reply_goes_to_list:0,reply_to:0,replyo:0,report_id:0,report_metadata:0,report_typ:0,reported_domain:0,reports_fold:0,repositori:0,req:0,request:0,request_uri:0,requir:0,resolv:0,respons:0,restart:0,restartsec:0,restor:0,result:0,retain:0,retriev:0,reus:0,revers:0,reverse_dn:0,review:0,rewrit:0,rfc2369:0,rfc822:0,rfc:0,rhel:0,right:0,rollup:0,root:0,rpm:0,rsa:0,rua:0,ruf:0,rule:0,safe:0,same:0,sameorigin:0,sample_headers_onli:0,save:0,save_aggreg:0,save_aggregate_report_to_elasticsearch:0,save_aggregate_reports_to_splunk:0,save_forens:0,save_forensic_report_to_elasticsearch:0,save_forensic_reports_to_splunk:0,save_output:0,schema:0,scope:0,scrub_nondigest:0,search:0,second:0,secret:0,secur:0,see:0,segment:0,selector:0,self:0,send:0,sensit:0,sent:0,separ:0,server:0,servernameon:0,session:0,set:0,set_host:0,setuptool:0,sha256:0,sha384:0,shard:0,share:0,sharepoint:0,should:0,shouldn:0,show:0,shv:0,side:0,sign:0,signatur:0,silent:0,similar:0,simpl:0,simplifi:0,singl:0,sister:0,site:0,size:0,skip:0,skip_certificate_verif:0,slightli:0,small:0,smtp:0,smtperror:0,socket:0,solut:0,some:0,someon:0,sometim:0,sort:0,source_base_domain:0,source_countri:0,source_ip_address:0,source_reverse_dn:0,sourceforg:0,special:0,specif:0,specifi:0,speed:0,spf_align:0,spf_domain:0,spf_result:0,spf_scope:0,splunk_hec:0,splunkerror:0,splunkhec:0,spoof:0,squeaki:0,ssl:0,ssl_cert_path:0,ssl_certif:0,ssl_certificate_kei:0,ssl_cipher:0,ssl_context:0,ssl_prefer_server_ciph:0,ssl_protocol:0,ssl_session_cach:0,ssl_session_ticket:0,ssl_session_timeout:0,sslcontext:0,stabl:0,standard:0,start:0,starttl:0,statu:0,step:0,still:0,storag:0,store:0,str:0,strict:0,string:0,strip:0,strip_attachment_payload:0,strongli:0,structur:0,subdomain:0,subject:0,subject_prefix:0,subsidiari:0,substitut:0,sudo:0,suffix:0,suggest:0,suppli:0,sure:0,sw50zxjha3rpdmugv2v0dgjld2vyymvylcocymvyc2ljahq:0,symlink:0,syslog:0,system:0,systemctl:0,tab:0,tag:0,tar:0,target:0,tby:0,tee:0,tell:0,templat:0,temporari:0,text:0,than:0,thank:0,thei:0,theirs:0,them:0,therebi:0,thi:0,thousand:0,three:0,through:0,time:0,timeout:0,timestamp:0,timestamp_to_datetim:0,timestamp_to_human:0,timezon:0,tld:0,tlsv1:0,to_domain:0,to_utc:0,token:0,tool:0,top:0,topic:0,touch:0,tracker:0,tradit:0,transfer:0,transpar:0,transport:0,trust:0,tweak:0,two:0,type:0,ubuntu:0,uncom:0,uncondition:0,under:0,underneath:0,understand:0,unfortun:0,uninstal:0,unit:0,unix:0,unsubscrib:0,unzip:0,updat:0,upersecur:0,upper:0,uri:0,url:0,usag:0,use:0,use_fresh_psl:0,use_ssl:0,used:0,useful:0,user:0,user_ag:0,useradd:0,usernam:0,uses:0,usesystemproxi:0,usr:0,utc:0,utf:0,valimail:0,valu:0,vendor:0,venv:0,veri:0,verif:0,verifi:0,version:0,vew:0,view:0,virtualenv:0,volum:0,vulner:0,w3c:0,wai:0,wait:0,want:0,wantedbi:0,warn:0,watch:0,watch_inbox:0,watcher:0,web:0,webdav:0,webmail:0,well:0,were:0,wettbewerb:0,wget:0,when:0,whenev:0,where:0,wherea:0,which:0,who:0,why:0,wide:0,wiki:0,window:0,without:0,work:0,workstat:0,worst:0,would:0,wrap:0,write:0,www:0,x509:0,xennn:0,xml:0,xml_schema:0,xms4g:0,xmx4g:0,yahoo:0,yet:0,you:0,your:0,yum:0,yyyi:0,zip:0},titles:["parsedmarc documentation - Open source DMARC report analyzer and visualizer"],titleterms:{EWS:0,Using:0,about:0,access:0,aggreg:0,align:0,analyz:0,api:0,best:0,bug:0,cli:0,configur:0,csv:0,dashboard:0,davmail:0,depend:0,dkim:0,dmarc:0,document:0,domain:0,elast:0,elasticsearch:0,featur:0,file:0,forens:0,guid:0,help:0,inbox:0,index:0,indic:0,instal:0,json:0,kibana:0,list:0,listserv:0,lookalik:0,mail:0,mailman:0,multipl:0,open:0,option:0,output:0,owa:0,parsedmarc:0,pattern:0,practic:0,pypy3:0,record:0,report:0,resourc:0,retent:0,run:0,sampl:0,sender:0,servic:0,sourc:0,spf:0,splunk:0,summari:0,support:0,systemd:0,tabl:0,test:0,upgrad:0,using:0,util:0,valid:0,visual:0,what:0,won:0,workaround:0}}) \ No newline at end of file +Search.setIndex({docnames:["index"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.todo":1,"sphinx.ext.viewcode":1,sphinx:56},filenames:["index.rst"],objects:{"":{parsedmarc:[0,0,0,"-"]},"parsedmarc.elastic":{AlreadySaved:[0,1,1,""],ElasticsearchError:[0,1,1,""],create_indexes:[0,2,1,""],migrate_indexes:[0,2,1,""],save_aggregate_report_to_elasticsearch:[0,2,1,""],save_forensic_report_to_elasticsearch:[0,2,1,""],set_hosts:[0,2,1,""]},"parsedmarc.splunk":{HECClient:[0,3,1,""],SplunkError:[0,1,1,""]},"parsedmarc.splunk.HECClient":{save_aggregate_reports_to_splunk:[0,4,1,""],save_forensic_reports_to_splunk:[0,4,1,""]},"parsedmarc.utils":{DownloadError:[0,1,1,""],EmailParserError:[0,1,1,""],convert_outlook_msg:[0,2,1,""],decode_base64:[0,2,1,""],get_base_domain:[0,2,1,""],get_filename_safe_string:[0,2,1,""],get_ip_address_country:[0,2,1,""],get_ip_address_info:[0,2,1,""],get_reverse_dns:[0,2,1,""],human_timestamp_to_datetime:[0,2,1,""],human_timestamp_to_timestamp:[0,2,1,""],is_outlook_msg:[0,2,1,""],parse_email:[0,2,1,""],query_dns:[0,2,1,""],timestamp_to_datetime:[0,2,1,""],timestamp_to_human:[0,2,1,""]},parsedmarc:{InvalidAggregateReport:[0,1,1,""],InvalidDMARCReport:[0,1,1,""],InvalidForensicReport:[0,1,1,""],ParserError:[0,1,1,""],elastic:[0,0,0,"-"],email_results:[0,2,1,""],extract_xml:[0,2,1,""],get_dmarc_reports_from_inbox:[0,2,1,""],get_imap_capabilities:[0,2,1,""],get_report_zip:[0,2,1,""],parse_aggregate_report_file:[0,2,1,""],parse_aggregate_report_xml:[0,2,1,""],parse_forensic_report:[0,2,1,""],parse_report_email:[0,2,1,""],parse_report_file:[0,2,1,""],parsed_aggregate_reports_to_csv:[0,2,1,""],parsed_forensic_reports_to_csv:[0,2,1,""],save_output:[0,2,1,""],splunk:[0,0,0,"-"],utils:[0,0,0,"-"],watch_inbox:[0,2,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","exception","Python exception"],"2":["py","function","Python function"],"3":["py","class","Python class"],"4":["py","method","Python method"]},objtypes:{"0":"py:module","1":"py:exception","2":"py:function","3":"py:class","4":"py:method"},terms:{"2017a":0,"50m":0,"\u00fcbersicht":0,"break":0,"byte":0,"case":0,"class":0,"default":0,"float":0,"function":0,"import":0,"int":0,"long":0,"new":0,"null":0,"public":0,"return":0,"switch":0,"true":0,"var":0,"while":0,And:0,DNS:0,For:0,OLE:0,TLS:0,That:0,The:0,Then:0,These:0,Use:0,Uses:0,With:0,Yes:0,_input:0,abl:0,abov:0,accept:0,access_token:0,accident:0,account:0,acm:0,across:0,action:0,actual:0,add:0,add_head:0,added:0,adding:0,addit:0,address:0,addresse:0,adkim:0,admin:0,administr:0,adsl:0,aes128:0,aes256:0,after:0,against:0,agari:0,age:0,aggregate_index:0,aggregate_report:0,aggregate_top:0,all:0,allow:0,allowremot:0,alreadysav:0,also:0,alter:0,altern:0,although:0,alwai:0,ani:0,anonym:0,anoth:0,answer:0,apach:0,apache2:0,appear:0,appendix:0,appli:0,approach:0,approxim:0,apt:0,archiv:0,archive_fold:0,argument:0,arriv:0,arrival_d:0,arrival_date_utc:0,artifact:0,ask:0,asmx:0,aspf:0,assign:0,associ:0,attach:0,attachment_filenam:0,auth:0,auth_bas:0,auth_basic_user_fil:0,auth_failur:0,auth_result:0,authent:0,authentication_mechan:0,authentication_result:0,auto:0,autodetect:[],avail:0,avoid:0,b2c:0,base64:0,base:0,base_domain:0,basic:0,bcc:0,bd6e1bb5:0,becaus:0,been:0,begin_d:0,behind:0,being:0,bellsouth:0,below:0,between:0,bin:0,binari:0,bind:0,bindaddress:0,bitbucket:0,blank:0,block:0,bodi:0,bool:0,brand:0,busi:0,button:0,bz2:0,cach:0,call:0,callback:0,came:0,can:0,capabl:0,caus:0,center:0,cento:0,cert:0,cert_path:0,certif:0,cest:0,chacha20:0,chain:0,chang:0,charact:0,charset:0,chart:0,check:0,checkbox:0,checkdmarc:0,chines:0,chmod:0,choos:0,chown:0,chunk_siz:0,cisco:0,click:0,client:0,clientsotimeout:0,cloudflar:0,code:0,collect:0,collector:0,com:0,come:0,comma:0,command:0,comment:0,commerci:0,common:0,commun:0,complet:0,compli:0,compliant:0,compress:0,config:0,config_fil:0,conform:0,connect:0,consid:0,consist:0,consolid:0,consum:0,contact:0,contain:0,content:0,context:[],control:0,convert:0,convert_outlook_msg:0,copi:0,core:0,correctli:0,could:0,count:0,countri:0,crash:0,creat:0,create_index:0,credenti:0,crt:0,csr:0,cumul:0,current:0,custom:0,daemon:0,dai:0,daili:0,dat:0,data:0,databas:0,date:0,date_utc:0,datetim:0,deb:0,debian:0,debug:0,decod:0,decode_base64:0,defens:0,delai:0,delet:0,delivery_result:0,demystifi:0,deploi:0,describ:0,descript:0,detail:0,develop:0,dict:0,dictionari:0,differ:0,digest:0,directli:0,directori:0,dis:0,disabl:0,disclaim:0,displai:0,display_nam:0,disposit:0,dkim_align:0,dkim_domain:0,dkim_result:0,dkim_selector:0,dkm:0,dmarc_aggreg:0,dmarc_forens:0,dmarc_moderation_act:0,dmarc_none_moderation_act:0,dmarc_quarentine_moderation_act:0,dmarcian:0,dmarcresport:0,dns_timeout:0,doctyp:0,doe:0,domainawar:0,don:0,down:0,download:0,downloaderror:0,draft:0,dtd:0,dure:0,each:0,earlier:0,easi:0,easier:0,easy_instal:0,ecdh:0,ecdsa:0,echo:0,edit:0,editor:0,effici:0,elasticsearcherror:0,els:0,email:0,email_result:0,emailparsererror:0,empti:0,enabl:0,enableew:0,enablekeepal:0,enableproxi:0,encod:0,encount:0,encrypt:0,end:0,end_dat:0,enforc:0,ensur:0,entir:0,envelop:0,envelope_from:0,envelope_to:0,environ:0,error:0,especi:0,etc:0,even:0,event:0,everi:0,exactli:0,exampl:0,exampleus:0,except:0,exchang:0,exclud:0,execstart:0,exist:0,exit:0,expiringdict:0,explain:0,explicit:0,extract:0,extract_xml:0,eyes:0,factor:0,fail:0,failur:0,fals:0,fantast:0,faster:0,feedback:0,feedback_report:0,feedback_typ:0,fetch:0,few:0,field:0,file_path:0,filenam:0,filename_safe_subject:0,fill:0,filter:0,financ:0,find:0,fine:0,first:0,first_strip_reply_to:0,fit:0,fix:0,flag:0,flat:0,flexibl:0,folder:0,foldersizelimit:0,follow:0,footer:0,fore:0,forensic_index:0,forensic_report:0,forensic_top:0,format:0,forward:0,found:0,foundat:0,fqdn:0,frame:0,fraud:0,free:0,fresh:0,friendli:0,from:0,from_is_list:0,ftp_proxi:0,full:0,fulli:0,further:0,gatewai:0,gcm:0,gdpr:0,gener:0,geoip:0,geoipupd:0,geolite2:0,geoloc:0,get:0,get_base_domain:0,get_dmarc_reports_from_inbox:0,get_filename_safe_str:0,get_imap_cap:0,get_ip_address_countri:0,get_ip_address_info:0,get_report_zip:0,get_reverse_dn:0,git:0,github:0,give:0,given:0,glass:0,global:0,gmail:0,goe:0,googl:0,gpg:0,graph:0,group:0,gzip:0,hand:0,handl:0,has:0,has_defect:0,have:0,head:0,header:0,header_from:0,headless:0,healthcar:0,heap:0,heavi:0,hec:0,hecclient:0,hectokengoesher:0,here:0,high:0,higher:0,highli:0,his:0,hop:0,host:0,hostnam:0,hover:0,href:0,html:0,htpasswd:0,http2:0,http:0,http_proxi:0,httpasswd:0,httpd:0,https_proxi:0,human:0,human_timestamp:0,human_timestamp_to_datetim:0,human_timestamp_to_timestamp:0,icon:0,ideal:0,ident:0,identifi:0,idl:0,idle_timeout:0,imap:0,imapalwaysapproxmsgs:0,imapautoexpung:0,imapcli:0,imaperror:[],imapidledelai:0,imapport:0,immedi:0,impli:0,improv:0,includ:0,include_list_post_head:0,include_rfc2369_head:0,include_sender_head:0,includesubdomain:0,incom:0,increas:0,index_suffix:0,industri:0,inform:0,ini:0,input_:0,insid:0,instanc:0,instead:0,intend:0,interact:0,interakt:0,interfer:0,invalid:0,invalidaggregatereport:0,invaliddmarcreport:0,invalidforensicreport:0,ip_address:0,ipv4:0,ipv6:0,is_outlook_msg:0,iso:0,issu:0,its:0,java:0,job:0,joe:0,journalctl:0,jre:0,just:0,jvm:0,jxf:0,kafka:0,kb4099855:0,kb4134118:0,kb4295699:0,keepal:0,kei:0,keyout:0,kibana_saved_object:0,kind:0,know:0,known:0,languag:0,larg:0,larger:0,later:0,latest:0,layout:0,leak:0,least:0,leav:0,left:0,legal:0,legitim:0,level:0,libemail:0,like:0,limit:0,line:0,link:0,linux:0,linux_x86_64:0,listen:0,load:0,local:0,localhost:0,locat:0,log:0,log_fil:0,login:0,longer:0,look:0,loopback:0,lot:0,lua:0,maco:0,magnifi:0,mai:0,mail_bcc:0,mail_cc:0,mail_from:0,mail_to:0,mailbox:0,mailer:0,mailrelai:0,mailto:0,main:0,make:0,malici:0,manag:0,manual:0,map:0,market:0,match:0,max:0,maximum:0,maxmind:0,mechan:0,member:0,mention:0,menu:0,messag:0,message_id:0,meta:0,mfrom:0,microsoft:0,might:0,migrate_index:0,mime:0,minimum:0,minut:0,mitig:0,mkdir:0,mmdb:0,mobil:0,mode:0,modern:0,modifi:0,modul:0,mon:0,monitor:0,monthli:0,monthly_index:0,more:0,most:0,mous:0,move:0,move_support:[],msg:0,msg_byte:0,msg_date:0,msg_footer:0,msg_header:0,msgconvert:0,much:0,multi:0,mung:0,must:0,n_proc:0,name:0,nameserv:0,nano:0,navig:0,ncontent:0,ndate:0,need:0,neeed:0,nelson:0,net:0,network:0,newest:0,newkei:0,next:0,nfrom:0,nginx:0,nmessag:0,nmime:0,node:0,non:0,none:0,noproxyfor:0,norepli:0,normal:0,nosecureimap:0,nosniff:0,notabl:0,now:0,nsubject:0,nto:0,number:0,number_of_replica:0,number_of_shard:0,nwettbewerb:0,object:0,observ:0,occur:0,occurr:0,oct:0,off:0,office365:0,offlin:0,often:0,old:0,older:0,oldest:0,ondmarc:0,one:0,onflin:0,onli:0,onlin:0,opendn:0,openssl:0,opt:0,ordereddict:0,org:0,org_email:0,org_extra_contact_info:0,org_nam:0,organ:0,organis:0,origin:0,original_envelope_id:0,original_mail_from:0,original_rcpt_to:0,other:0,our:0,out:0,outdat:0,outgo:0,outlook:0,output_directori:0,outsid:0,over:0,overrid:0,overwrit:0,own:0,pack:0,packag:0,pad:0,page:0,pan:0,parallel:0,param:0,paramet:0,parent:0,pars:0,parse_aggregate_report_fil:0,parse_aggregate_report_xml:0,parse_email:0,parse_forensic_report:0,parse_report_email:0,parse_report_fil:0,parsed_aggregate_reports_to_csv:0,parsed_forensic_reports_to_csv:0,parsed_sampl:0,parser:0,parsererror:0,part:0,particular:0,particularli:0,pass:0,passag:0,passsword:0,password:0,past:0,patch:0,path:0,payload:0,pct:0,percentag:0,perform:0,period:0,perl:0,permiss:0,peter:0,pie:0,pip3:0,pip:0,place:0,plain:0,plaintext:0,platform:0,pleas:0,plu:0,polici:0,policy_evalu:0,policy_override_com:0,policy_override_reason:0,policy_publish:0,poll:0,poly1305:0,port:0,portabl:0,posit:0,possibl:0,post:0,poster:0,postoriu:0,prefix:0,preload:0,premad:0,previou:0,previous:0,print:0,printabl:0,privaci:0,process:0,produc:0,product:0,program:0,project:0,prompt:0,proofpoint:0,properti:0,protect:0,provid:0,prox:0,proxi:0,proxy_add_x_forwarded_for:0,proxy_pass:0,proxy_set_head:0,proxyhost:0,proxypassword:0,proxyport:0,proxyus:0,pry:0,public_suffix_list:0,publicsuffix:0,publish:0,pypi:0,python34:0,python3:0,python:0,quarantin:0,queri:0,query_dn:0,quot:0,rais:0,ram:0,rasi:0,rather:0,readabl:0,readonlyrest:0,real:0,realli:0,reason:0,receiv:0,recipi:0,recogn:0,recommend:0,record_typ:0,refer:0,regardless:0,regul:0,regular:0,reject:0,relai:0,relat:0,releas:0,reli:0,reliabl:0,reload:0,remain:0,remot:0,remote_addr:0,remov:0,repeat:0,replac:0,repli:0,replica:0,reply_goes_to_list:0,reply_to:0,replyo:0,report_id:0,report_metadata:0,report_typ:0,reported_domain:0,reports_fold:0,repositori:0,req:0,request:0,request_uri:0,requir:0,require_encrypt:0,resolv:0,respons:0,restart:0,restartsec:0,restor:0,result:0,retain:0,retriev:0,reus:0,revers:0,reverse_dn:0,review:0,rewrit:0,rfc2369:0,rfc822:0,rfc:0,rhel:0,right:0,rollup:0,root:0,rpm:0,rsa:0,rua:0,ruf:0,rule:0,safe:0,same:0,sameorigin:0,sample_headers_onli:0,save:0,save_aggreg:0,save_aggregate_report_to_elasticsearch:0,save_aggregate_reports_to_splunk:0,save_forens:0,save_forensic_report_to_elasticsearch:0,save_forensic_reports_to_splunk:0,save_output:0,schema:0,scope:0,scrub_nondigest:0,search:0,second:0,secret:0,secur:0,see:0,segment:0,selector:0,self:0,send:0,sensit:0,sent:0,separ:0,server:0,servernameon:0,session:0,set:0,set_host:0,setuptool:0,sha256:0,sha384:0,shard:0,share:0,sharepoint:0,should:0,shouldn:0,show:0,shv:0,side:0,sign:0,signatur:0,silent:0,similar:0,simpl:0,simplifi:0,singl:0,sister:0,site:0,size:0,skip:0,skip_certificate_verif:0,slightli:0,small:0,smtp:0,smtperror:[],socket:0,solut:0,some:0,someon:0,sometim:0,sort:0,source_base_domain:0,source_countri:0,source_ip_address:0,source_reverse_dn:0,sourceforg:0,special:0,specif:0,specifi:0,speed:0,spf_align:0,spf_domain:0,spf_result:0,spf_scope:0,splunk_hec:0,splunkerror:0,splunkhec:0,spoof:0,squeaki:0,ssl:0,ssl_cert_path:0,ssl_certif:0,ssl_certificate_kei:0,ssl_cipher:0,ssl_context:[],ssl_prefer_server_ciph:0,ssl_protocol:0,ssl_session_cach:0,ssl_session_ticket:0,ssl_session_timeout:0,sslcontext:[],stabl:0,standard:0,start:0,starttl:0,statu:0,step:0,still:0,storag:0,store:0,str:0,strict:0,string:0,strip:0,strip_attachment_payload:0,strongli:0,structur:0,subdomain:0,subject:0,subject_prefix:0,subsidiari:0,substitut:0,sudo:0,suffix:0,suggest:0,suppli:0,sure:0,sw50zxjha3rpdmugv2v0dgjld2vyymvylcocymvyc2ljahq:0,symlink:0,syslog:0,system:0,systemctl:0,tab:0,tag:0,tar:0,target:0,tby:0,tee:0,tell:0,templat:0,temporari:0,text:0,than:0,thank:0,thei:0,theirs:0,them:0,therebi:0,thi:0,thousand:0,three:0,through:0,time:0,timeout:0,timestamp:0,timestamp_to_datetim:0,timestamp_to_human:0,timezon:0,tld:0,tlsv1:0,to_domain:0,to_utc:0,token:0,tool:0,top:0,topic:0,touch:0,tracker:0,tradit:0,transfer:0,transpar:0,transport:0,trust:0,tweak:0,two:0,type:0,ubuntu:0,uncom:0,uncondition:0,under:0,underneath:0,understand:0,unfortun:0,uninstal:0,unit:0,unix:0,unsubscrib:0,unzip:0,updat:0,upersecur:0,upper:0,uri:0,url:0,usag:0,use:0,use_fresh_psl:0,use_ssl:0,used:0,useful:0,user:0,user_ag:0,useradd:0,usernam:0,uses:0,usesystemproxi:0,usr:0,utc:0,utf:0,valimail:0,valu:0,vendor:0,venv:0,veri:0,verif:0,verifi:0,version:0,vew:0,view:0,virtualenv:0,volum:0,vulner:0,w3c:0,wai:0,wait:0,want:0,wantedbi:0,warn:0,watch:0,watch_inbox:0,watcher:0,web:0,webdav:0,webmail:0,well:0,were:0,wettbewerb:0,wget:0,when:0,whenev:0,where:0,wherea:0,which:0,who:0,why:0,wide:0,wiki:0,window:0,without:0,work:0,workstat:0,worst:0,would:0,wrap:0,write:0,www:0,x509:0,xennn:0,xml:0,xml_schema:0,xms4g:0,xmx4g:0,yahoo:0,yet:0,you:0,your:0,yum:0,yyyi:0,zip:0},titles:["parsedmarc documentation - Open source DMARC report analyzer and visualizer"],titleterms:{EWS:0,Using:0,about:0,access:0,aggreg:0,align:0,analyz:0,api:0,best:0,bug:0,cli:0,configur:0,csv:0,dashboard:0,davmail:0,depend:0,dkim:0,dmarc:0,document:0,domain:0,elast:0,elasticsearch:0,featur:0,file:0,forens:0,guid:0,help:0,inbox:0,index:0,indic:0,instal:0,json:0,kibana:0,list:0,listserv:0,lookalik:0,mail:0,mailman:0,multipl:0,open:0,option:0,output:0,owa:0,parsedmarc:0,pattern:0,practic:0,pypy3:0,record:0,report:0,resourc:0,retent:0,run:0,sampl:0,sender:0,servic:0,sourc:0,spf:0,splunk:0,summari:0,support:0,systemd:0,tabl:0,test:0,upgrad:0,using:0,util:0,valid:0,visual:0,what:0,won:0,workaround:0}}) \ No newline at end of file