mirror of
https://github.com/domainaware/parsedmarc.git
synced 2026-08-02 13:42:19 +00:00
Update docs
This commit is contained in:
+4
-3
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Overview: module code — parsedmarc 10.3.0 documentation</title>
|
||||
<title>Overview: module code — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="../_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="../_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="../_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="../_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="../_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="../_static/js/theme.js"></script>
|
||||
@@ -79,7 +79,8 @@
|
||||
|
||||
<h1>All modules for which code is available</h1>
|
||||
<ul><li><a href="parsedmarc.html">parsedmarc</a></li>
|
||||
<ul><li><a href="parsedmarc/elastic.html">parsedmarc.elastic</a></li>
|
||||
<ul><li><a href="parsedmarc/config.html">parsedmarc.config</a></li>
|
||||
<li><a href="parsedmarc/elastic.html">parsedmarc.elastic</a></li>
|
||||
<li><a href="parsedmarc/opensearch.html">parsedmarc.opensearch</a></li>
|
||||
<li><a href="parsedmarc/splunk.html">parsedmarc.splunk</a></li>
|
||||
<li><a href="parsedmarc/types.html">parsedmarc.types</a></li>
|
||||
|
||||
+901
-300
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,298 @@
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html class="writer-html5" lang="en" data-content_root="../../">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>parsedmarc.config — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="../../_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="../../_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="../../_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="../../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="../../_static/js/theme.js"></script>
|
||||
<link rel="index" title="Index" href="../../genindex.html" />
|
||||
<link rel="search" title="Search" href="../../search.html" />
|
||||
</head>
|
||||
|
||||
<body class="wy-body-for-nav">
|
||||
<div class="wy-grid-for-nav">
|
||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
||||
<div class="wy-side-scroll">
|
||||
<div class="wy-side-nav-search" >
|
||||
|
||||
|
||||
|
||||
<a href="../../index.html" class="icon icon-home">
|
||||
parsedmarc
|
||||
</a>
|
||||
<div role="search">
|
||||
<form id="rtd-search-form" class="wy-form" action="../../search.html" method="get">
|
||||
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
</form>
|
||||
</div>
|
||||
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
|
||||
<p class="caption" role="heading"><span class="caption-text">Contents</span></p>
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="../../installation.html">Installation</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="../../usage.html">Using parsedmarc</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="../../output.html">Sample outputs</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="../../elasticsearch.html">Elasticsearch and Kibana</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="../../opensearch.html">OpenSearch and Grafana</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="../../kibana.html">Using the Kibana dashboards</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="../../splunk.html">Splunk</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="../../davmail.html">Accessing an inbox using OWA/EWS</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="../../dmarc.html">Understanding DMARC</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="../../contributing.html">Contributing to parsedmarc</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="../../api.html">API reference</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
|
||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||
<a href="../../index.html">parsedmarc</a>
|
||||
</nav>
|
||||
|
||||
<div class="wy-nav-content">
|
||||
<div class="rst-content">
|
||||
<div role="navigation" aria-label="Page navigation">
|
||||
<ul class="wy-breadcrumbs">
|
||||
<li><a href="../../index.html" class="icon icon-home" aria-label="Home"></a></li>
|
||||
<li class="breadcrumb-item"><a href="../index.html">Module code</a></li>
|
||||
<li class="breadcrumb-item"><a href="../parsedmarc.html">parsedmarc</a></li>
|
||||
<li class="breadcrumb-item active">parsedmarc.config</li>
|
||||
<li class="wy-breadcrumbs-aside">
|
||||
</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
</div>
|
||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||
<div itemprop="articleBody">
|
||||
|
||||
<h1>Source code for parsedmarc.config</h1><div class="highlight"><pre>
|
||||
<span></span><span class="c1"># -*- coding: utf-8 -*-</span>
|
||||
|
||||
<span class="sd">"""Centralized parser configuration (GitHub issue #503).</span>
|
||||
|
||||
<span class="sd">This module defines :class:`ParserConfig`, a single frozen dataclass that</span>
|
||||
<span class="sd">carries every parsing/enrichment option (offline mode, IP database path,</span>
|
||||
<span class="sd">reverse DNS map location, PSL overrides location, DNS behavior, etc.) plus</span>
|
||||
<span class="sd">the three caches that the parser and enrichment code share across calls:</span>
|
||||
<span class="sd">the IP address info cache, the seen-aggregate-report-ID cache, and the</span>
|
||||
<span class="sd">reverse DNS map.</span>
|
||||
|
||||
<span class="sd">``parsedmarc/__init__.py`` re-exports :data:`IP_ADDRESS_CACHE`,</span>
|
||||
<span class="sd">:data:`SEEN_AGGREGATE_REPORT_IDS`, and :data:`REVERSE_DNS_MAP` under the</span>
|
||||
<span class="sd">same names for backward compatibility. That compatibility is</span>
|
||||
<span class="sd">identity-based: ``parsedmarc.IP_ADDRESS_CACHE is parsedmarc.config.IP_ADDRESS_CACHE``</span>
|
||||
<span class="sd">must hold, not merely equal contents, since callers may mutate the caches</span>
|
||||
<span class="sd">in place.</span>
|
||||
|
||||
<span class="sd">Only :mod:`parsedmarc.constants` and :mod:`parsedmarc.utils` are imported</span>
|
||||
<span class="sd">from the package here — importing :mod:`parsedmarc` itself would be</span>
|
||||
<span class="sd">circular, since ``parsedmarc/__init__.py`` imports from this module.</span>
|
||||
<span class="sd">"""</span>
|
||||
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">__future__</span><span class="w"> </span><span class="kn">import</span> <span class="n">annotations</span>
|
||||
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">dataclasses</span><span class="w"> </span><span class="kn">import</span> <span class="n">dataclass</span><span class="p">,</span> <span class="n">field</span><span class="p">,</span> <span class="n">fields</span>
|
||||
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">expiringdict</span><span class="w"> </span><span class="kn">import</span> <span class="n">ExpiringDict</span>
|
||||
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">parsedmarc.constants</span><span class="w"> </span><span class="kn">import</span> <span class="n">DEFAULT_DNS_MAX_RETRIES</span><span class="p">,</span> <span class="n">DEFAULT_DNS_TIMEOUT</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">parsedmarc.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">ReverseDNSMap</span>
|
||||
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">_new_ip_address_cache</span><span class="p">()</span> <span class="o">-></span> <span class="n">ExpiringDict</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""Build a fresh IP-address-info cache (4 hour expiry)."""</span>
|
||||
<span class="k">return</span> <span class="n">ExpiringDict</span><span class="p">(</span><span class="n">max_len</span><span class="o">=</span><span class="mi">10000</span><span class="p">,</span> <span class="n">max_age_seconds</span><span class="o">=</span><span class="mi">14400</span><span class="p">)</span>
|
||||
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">_new_seen_aggregate_report_ids</span><span class="p">()</span> <span class="o">-></span> <span class="n">ExpiringDict</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""Build a fresh seen-aggregate-report-ID cache (1 hour expiry)."""</span>
|
||||
<span class="k">return</span> <span class="n">ExpiringDict</span><span class="p">(</span><span class="n">max_len</span><span class="o">=</span><span class="mi">100000000</span><span class="p">,</span> <span class="n">max_age_seconds</span><span class="o">=</span><span class="mi">3600</span><span class="p">)</span>
|
||||
|
||||
|
||||
<span class="c1"># Canonical default caches. parsedmarc/__init__.py re-exports these three</span>
|
||||
<span class="c1"># objects under the same names (IP_ADDRESS_CACHE, SEEN_AGGREGATE_REPORT_IDS,</span>
|
||||
<span class="c1"># REVERSE_DNS_MAP) for backward compatibility with code that imported them</span>
|
||||
<span class="c1"># directly from the top-level package. That compatibility promise is</span>
|
||||
<span class="c1"># identity-based — the re-exported names must point at these very same</span>
|
||||
<span class="c1"># objects, not merely equivalent ones — so that library callers who obtained</span>
|
||||
<span class="c1"># a reference before this refactor keep observing the same mutations as code</span>
|
||||
<span class="c1"># that goes through a ParserConfig built from these defaults (e.g. during</span>
|
||||
<span class="c1"># unpickling in a multiprocessing worker; see ParserConfig.__setstate__).</span>
|
||||
<span class="n">IP_ADDRESS_CACHE</span> <span class="o">=</span> <span class="n">_new_ip_address_cache</span><span class="p">()</span>
|
||||
<span class="n">SEEN_AGGREGATE_REPORT_IDS</span> <span class="o">=</span> <span class="n">_new_seen_aggregate_report_ids</span><span class="p">()</span>
|
||||
<span class="n">REVERSE_DNS_MAP</span><span class="p">:</span> <span class="n">ReverseDNSMap</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
|
||||
<span class="c1"># The ParserConfig fields excluded from pickling; every other field must</span>
|
||||
<span class="c1"># survive the round-trip, so __getstate__ derives its contents from</span>
|
||||
<span class="c1"># dataclasses.fields() rather than enumerating option fields by hand.</span>
|
||||
<span class="n">_CACHE_FIELD_NAMES</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="s2">"ip_address_cache"</span><span class="p">,</span>
|
||||
<span class="s2">"seen_aggregate_report_ids"</span><span class="p">,</span>
|
||||
<span class="s2">"reverse_dns_map"</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="ParserConfig">
|
||||
<a class="viewcode-back" href="../../api.html#parsedmarc.config.ParserConfig">[docs]</a>
|
||||
<span class="nd">@dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">ParserConfig</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""Carries all parsing/enrichment options, plus the caches they share.</span>
|
||||
|
||||
<span class="sd"> When passed as ``config=`` to parsedmarc's public parsing functions, the</span>
|
||||
<span class="sd"> individual option keyword arguments (``offline``, ``ip_db_path``,</span>
|
||||
<span class="sd"> ``nameservers``, etc.) are ignored in favor of the values carried on this</span>
|
||||
<span class="sd"> object.</span>
|
||||
|
||||
<span class="sd"> Every explicitly constructed ``ParserConfig()`` owns fresh, isolated</span>
|
||||
<span class="sd"> cache objects (``ip_address_cache``, ``seen_aggregate_report_ids``,</span>
|
||||
<span class="sd"> ``reverse_dns_map``) via ``default_factory`` — two independently</span>
|
||||
<span class="sd"> constructed configs never share cache state. To derive a variant of an</span>
|
||||
<span class="sd"> existing config that *does* keep sharing its caches (e.g. to override</span>
|
||||
<span class="sd"> ``offline`` for one call while still benefiting from warm caches), use</span>
|
||||
<span class="sd"> ``dataclasses.replace(cfg, ...)``: since every field, including the three</span>
|
||||
<span class="sd"> cache fields, is an init field, ``replace()`` copies the source's cache</span>
|
||||
<span class="sd"> objects onto the new instance rather than constructing fresh ones.</span>
|
||||
|
||||
<span class="sd"> Pickling (as happens when a config is captured in a</span>
|
||||
<span class="sd"> ``functools.partial`` payload submitted to a multiprocessing worker)</span>
|
||||
<span class="sd"> intentionally drops cache *contents*: ``__getstate__`` omits the three</span>
|
||||
<span class="sd"> cache fields, and ``__setstate__`` rebinds them to this module's</span>
|
||||
<span class="sd"> :data:`IP_ADDRESS_CACHE`, :data:`SEEN_AGGREGATE_REPORT_IDS`, and</span>
|
||||
<span class="sd"> :data:`REVERSE_DNS_MAP` — the unpickling process's module-default</span>
|
||||
<span class="sd"> caches — rather than either the sender's cache contents (which would be</span>
|
||||
<span class="sd"> expensive and stale to serialize per task) or brand new empty caches per</span>
|
||||
<span class="sd"> unpickle (which would silently defeat per-worker caching, since a</span>
|
||||
<span class="sd"> ``functools.partial`` payload is re-pickled for every task submitted to a</span>
|
||||
<span class="sd"> worker). Binding the module defaults means a freshly spawned worker</span>
|
||||
<span class="sd"> interpreter starts with empty caches and accumulates hits across the</span>
|
||||
<span class="sd"> tasks it handles, matching pre-refactor behavior.</span>
|
||||
|
||||
<span class="sd"> Note that ``keep_alive`` and ``n_procs`` are deliberately **not** fields</span>
|
||||
<span class="sd"> on this class: those control process/worker orchestration, not parsing</span>
|
||||
<span class="sd"> or enrichment behavior.</span>
|
||||
|
||||
<span class="sd"> Attributes:</span>
|
||||
<span class="sd"> offline: Do not make online requests (DNS, IP database download,</span>
|
||||
<span class="sd"> reverse DNS map download, PSL overrides download).</span>
|
||||
<span class="sd"> ip_db_path: Path to a local MMDB file from IPinfo, MaxMind, or DBIP.</span>
|
||||
<span class="sd"> always_use_local_files: Always use local/bundled files instead of</span>
|
||||
<span class="sd"> downloading the IP database, reverse DNS map, or PSL overrides.</span>
|
||||
<span class="sd"> reverse_dns_map_path: Path to a local reverse DNS map file.</span>
|
||||
<span class="sd"> reverse_dns_map_url: URL to a reverse DNS map file.</span>
|
||||
<span class="sd"> psl_overrides_path: Path to a local PSL overrides file.</span>
|
||||
<span class="sd"> psl_overrides_url: URL to a PSL overrides file.</span>
|
||||
<span class="sd"> nameservers: A list of one or more nameservers to use for DNS</span>
|
||||
<span class="sd"> queries (Cloudflare's public DNS resolvers by default).</span>
|
||||
<span class="sd"> dns_timeout: DNS query timeout, in seconds.</span>
|
||||
<span class="sd"> dns_retries: Number of times to retry a DNS query after a timeout or</span>
|
||||
<span class="sd"> other transient error.</span>
|
||||
<span class="sd"> strip_attachment_payloads: Remove attachment payloads from parsed</span>
|
||||
<span class="sd"> email results.</span>
|
||||
<span class="sd"> normalize_timespan_threshold_hours: Aggregate reports whose</span>
|
||||
<span class="sd"> timespan exceeds this many hours are normalized/split.</span>
|
||||
<span class="sd"> ip_address_cache: Cache of IP address enrichment results.</span>
|
||||
<span class="sd"> seen_aggregate_report_ids: Cache of already-seen aggregate report</span>
|
||||
<span class="sd"> IDs, used for de-duplication.</span>
|
||||
<span class="sd"> reverse_dns_map: The reverse DNS map used to classify base domains</span>
|
||||
<span class="sd"> found via reverse DNS.</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="n">offline</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
<span class="n">ip_db_path</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="n">always_use_local_files</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
<span class="n">reverse_dns_map_path</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="n">reverse_dns_map_url</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="n">psl_overrides_path</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="n">psl_overrides_url</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="n">nameservers</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="n">dns_timeout</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="n">DEFAULT_DNS_TIMEOUT</span>
|
||||
<span class="n">dns_retries</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="n">DEFAULT_DNS_MAX_RETRIES</span>
|
||||
<span class="n">strip_attachment_payloads</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
<span class="n">normalize_timespan_threshold_hours</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">24.0</span>
|
||||
<span class="n">ip_address_cache</span><span class="p">:</span> <span class="n">ExpiringDict</span> <span class="o">=</span> <span class="n">field</span><span class="p">(</span>
|
||||
<span class="n">default_factory</span><span class="o">=</span><span class="n">_new_ip_address_cache</span><span class="p">,</span> <span class="nb">repr</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">compare</span><span class="o">=</span><span class="kc">False</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">seen_aggregate_report_ids</span><span class="p">:</span> <span class="n">ExpiringDict</span> <span class="o">=</span> <span class="n">field</span><span class="p">(</span>
|
||||
<span class="n">default_factory</span><span class="o">=</span><span class="n">_new_seen_aggregate_report_ids</span><span class="p">,</span> <span class="nb">repr</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">compare</span><span class="o">=</span><span class="kc">False</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">reverse_dns_map</span><span class="p">:</span> <span class="n">ReverseDNSMap</span> <span class="o">=</span> <span class="n">field</span><span class="p">(</span>
|
||||
<span class="n">default_factory</span><span class="o">=</span><span class="nb">dict</span><span class="p">,</span> <span class="nb">repr</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">compare</span><span class="o">=</span><span class="kc">False</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">__getstate__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">object</span><span class="p">]:</span>
|
||||
<span class="w"> </span><span class="sd">"""Return picklable state, excluding the three cache fields.</span>
|
||||
|
||||
<span class="sd"> Cache contents are process-local and potentially huge; they are</span>
|
||||
<span class="sd"> never serialized. See the class docstring for the full rationale.</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">return</span> <span class="p">{</span>
|
||||
<span class="n">f</span><span class="o">.</span><span class="n">name</span><span class="p">:</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">f</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
|
||||
<span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">fields</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">f</span><span class="o">.</span><span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">_CACHE_FIELD_NAMES</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">__setstate__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">object</span><span class="p">])</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""Restore option fields, then rebind caches to this module's</span>
|
||||
<span class="sd"> process-wide defaults (never fresh empty caches — see the class</span>
|
||||
<span class="sd"> docstring for why that would silently break per-worker caching).</span>
|
||||
|
||||
<span class="sd"> Non-cache fields are first initialized to their class defaults, so</span>
|
||||
<span class="sd"> unpickling a ``ParserConfig`` serialized by an older parsedmarc</span>
|
||||
<span class="sd"> version (whose state predates fields added since) leaves the newer</span>
|
||||
<span class="sd"> fields at their defaults instead of unset entirely — ``__init__``</span>
|
||||
<span class="sd"> never runs during unpickling, so without this an absent field would</span>
|
||||
<span class="sd"> raise ``AttributeError`` on first access.</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">fields</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="n">f</span><span class="o">.</span><span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">_CACHE_FIELD_NAMES</span><span class="p">:</span>
|
||||
<span class="nb">object</span><span class="o">.</span><span class="fm">__setattr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">f</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">f</span><span class="o">.</span><span class="n">default</span><span class="p">)</span>
|
||||
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">state</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
|
||||
<span class="nb">object</span><span class="o">.</span><span class="fm">__setattr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
|
||||
<span class="nb">object</span><span class="o">.</span><span class="fm">__setattr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">"ip_address_cache"</span><span class="p">,</span> <span class="n">IP_ADDRESS_CACHE</span><span class="p">)</span>
|
||||
<span class="nb">object</span><span class="o">.</span><span class="fm">__setattr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">"seen_aggregate_report_ids"</span><span class="p">,</span> <span class="n">SEEN_AGGREGATE_REPORT_IDS</span><span class="p">)</span>
|
||||
<span class="nb">object</span><span class="o">.</span><span class="fm">__setattr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">"reverse_dns_map"</span><span class="p">,</span> <span class="n">REVERSE_DNS_MAP</span><span class="p">)</span></div>
|
||||
|
||||
</pre></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div role="contentinfo">
|
||||
<p>© Copyright 2018 - 2025, Sean Whalen and contributors.</p>
|
||||
</div>
|
||||
|
||||
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
||||
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
||||
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||
|
||||
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<script>
|
||||
jQuery(function () {
|
||||
SphinxRtdTheme.Navigation.enable(true);
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>parsedmarc.elastic — parsedmarc 10.3.0 documentation</title>
|
||||
<title>parsedmarc.elastic — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="../../_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="../../_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="../../_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="../../_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="../../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="../../_static/js/theme.js"></script>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>parsedmarc.opensearch — parsedmarc 10.3.0 documentation</title>
|
||||
<title>parsedmarc.opensearch — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="../../_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="../../_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="../../_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="../../_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="../../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="../../_static/js/theme.js"></script>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>parsedmarc.splunk — parsedmarc 10.3.0 documentation</title>
|
||||
<title>parsedmarc.splunk — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="../../_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="../../_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="../../_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="../../_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="../../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="../../_static/js/theme.js"></script>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>parsedmarc.types — parsedmarc 10.3.0 documentation</title>
|
||||
<title>parsedmarc.types — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="../../_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="../../_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="../../_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="../../_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="../../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="../../_static/js/theme.js"></script>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>parsedmarc.utils — parsedmarc 10.3.0 documentation</title>
|
||||
<title>parsedmarc.utils — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="../../_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="../../_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="../../_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="../../_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="../../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="../../_static/js/theme.js"></script>
|
||||
@@ -983,6 +983,8 @@
|
||||
<span class="n">url</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">offline</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">reverse_dns_map</span><span class="p">:</span> <span class="n">ReverseDNSMap</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">psl_overrides_path</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">psl_overrides_url</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="p">)</span> <span class="o">-></span> <span class="n">ReverseDNSService</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> Returns the service name of a given base domain name from reverse DNS.</span>
|
||||
@@ -991,9 +993,11 @@
|
||||
<span class="sd"> base_domain (str): The base domain of the reverse DNS lookup</span>
|
||||
<span class="sd"> always_use_local_file (bool): Always use a local map file</span>
|
||||
<span class="sd"> local_file_path (str): Path to a local map file</span>
|
||||
<span class="sd"> url (str): URL ro a reverse DNS map</span>
|
||||
<span class="sd"> url (str): URL to a reverse DNS map</span>
|
||||
<span class="sd"> offline (bool): Use the built-in copy of the reverse DNS map</span>
|
||||
<span class="sd"> reverse_dns_map (dict): A reverse DNS map</span>
|
||||
<span class="sd"> psl_overrides_path (str): Path to a local PSL overrides file</span>
|
||||
<span class="sd"> psl_overrides_url (str): URL to a PSL overrides file</span>
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> dict: A dictionary containing name and type.</span>
|
||||
<span class="sd"> If the service is unknown, the name will be</span>
|
||||
@@ -1014,6 +1018,8 @@
|
||||
<span class="n">local_file_path</span><span class="o">=</span><span class="n">local_file_path</span><span class="p">,</span>
|
||||
<span class="n">url</span><span class="o">=</span><span class="n">url</span><span class="p">,</span>
|
||||
<span class="n">offline</span><span class="o">=</span><span class="n">offline</span><span class="p">,</span>
|
||||
<span class="n">psl_overrides_path</span><span class="o">=</span><span class="n">psl_overrides_path</span><span class="p">,</span>
|
||||
<span class="n">psl_overrides_url</span><span class="o">=</span><span class="n">psl_overrides_url</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="n">service</span><span class="p">:</span> <span class="n">ReverseDNSService</span>
|
||||
@@ -1041,6 +1047,8 @@
|
||||
<span class="n">nameservers</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">timeout</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="n">DEFAULT_DNS_TIMEOUT</span><span class="p">,</span>
|
||||
<span class="n">retries</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="n">DEFAULT_DNS_MAX_RETRIES</span><span class="p">,</span>
|
||||
<span class="n">psl_overrides_path</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">psl_overrides_url</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="p">)</span> <span class="o">-></span> <span class="n">IPAddressInfo</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> Returns reverse DNS and country information for the given IP address</span>
|
||||
@@ -1059,6 +1067,8 @@
|
||||
<span class="sd"> timeout (float): Sets the DNS timeout in seconds</span>
|
||||
<span class="sd"> retries (int): Number of times to retry on timeout or other transient</span>
|
||||
<span class="sd"> errors</span>
|
||||
<span class="sd"> psl_overrides_path (str): Path to a local PSL overrides file</span>
|
||||
<span class="sd"> psl_overrides_url (str): URL to a PSL overrides file</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> dict: ``ip_address``, ``reverse_dns``, ``country``</span>
|
||||
@@ -1111,6 +1121,8 @@
|
||||
<span class="n">url</span><span class="o">=</span><span class="n">reverse_dns_map_url</span><span class="p">,</span>
|
||||
<span class="n">always_use_local_file</span><span class="o">=</span><span class="n">always_use_local_files</span><span class="p">,</span>
|
||||
<span class="n">reverse_dns_map</span><span class="o">=</span><span class="n">reverse_dns_map</span><span class="p">,</span>
|
||||
<span class="n">psl_overrides_path</span><span class="o">=</span><span class="n">psl_overrides_path</span><span class="p">,</span>
|
||||
<span class="n">psl_overrides_url</span><span class="o">=</span><span class="n">psl_overrides_url</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"base_domain"</span><span class="p">]</span> <span class="o">=</span> <span class="n">base_domain</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"type"</span><span class="p">]</span> <span class="o">=</span> <span class="n">service</span><span class="p">[</span><span class="s2">"type"</span><span class="p">]</span>
|
||||
@@ -1130,6 +1142,8 @@
|
||||
<span class="n">local_file_path</span><span class="o">=</span><span class="n">reverse_dns_map_path</span><span class="p">,</span>
|
||||
<span class="n">url</span><span class="o">=</span><span class="n">reverse_dns_map_url</span><span class="p">,</span>
|
||||
<span class="n">offline</span><span class="o">=</span><span class="n">offline</span><span class="p">,</span>
|
||||
<span class="n">psl_overrides_path</span><span class="o">=</span><span class="n">psl_overrides_path</span><span class="p">,</span>
|
||||
<span class="n">psl_overrides_url</span><span class="o">=</span><span class="n">psl_overrides_url</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">info</span><span class="p">[</span><span class="s2">"as_domain"</span><span class="p">]</span> <span class="ow">and</span> <span class="n">info</span><span class="p">[</span><span class="s2">"as_domain"</span><span class="p">]</span> <span class="ow">in</span> <span class="n">map_value</span><span class="p">:</span>
|
||||
<span class="n">service</span> <span class="o">=</span> <span class="n">map_value</span><span class="p">[</span><span class="n">info</span><span class="p">[</span><span class="s2">"as_domain"</span><span class="p">]]</span>
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
:members:
|
||||
```
|
||||
|
||||
## parsedmarc.config
|
||||
|
||||
```{eval-rst}
|
||||
.. automodule:: parsedmarc.config
|
||||
:members:
|
||||
```
|
||||
|
||||
## parsedmarc.elastic
|
||||
|
||||
```{eval-rst}
|
||||
|
||||
@@ -38,7 +38,7 @@ valid when a message is forwarded without changing the from address, which is
|
||||
often caused by a mailbox forwarding rule. This is because DKIM signatures are
|
||||
part of the message headers, whereas SPF relies on SMTP session headers.
|
||||
|
||||
Underneath the pie charts. you can see graphs of DMARC passage and message
|
||||
Underneath the pie charts, you can see graphs of DMARC compliance and message
|
||||
disposition over time.
|
||||
|
||||
Under the graphs you will find the most useful data tables on the dashboard. On
|
||||
|
||||
@@ -18,5 +18,5 @@ The Splunk dashboards display the same content and layout as the
|
||||
Kibana dashboards, although the Kibana dashboards have slightly
|
||||
easier and more flexible filtering options.
|
||||
|
||||
[xml files]: https://github.com/domainaware/parsedmarc/tree/master/splunk
|
||||
[xml files]: https://github.com/domainaware/parsedmarc/tree/master/dashboards/splunk
|
||||
[http event collector (hec)]: http://docs.splunk.com/Documentation/Splunk/latest/Data/AboutHEC
|
||||
|
||||
+192
-9
@@ -132,6 +132,24 @@ The full set of configuration options are:
|
||||
payloads from results
|
||||
- `silent` - bool: Set this to `False` to output results to STDOUT
|
||||
- `output` - str: Directory to place JSON and CSV files in. This is required if you set either of the JSON output file options.
|
||||
- `archive_directory` - str: Optional. When set, successfully
|
||||
processed report files given as local file/directory path
|
||||
arguments are moved into
|
||||
`<archive_directory>/<year>/<month>/<Aggregate|Failure|SMTP-TLS>/`
|
||||
(year and month come from the report's own begin/arrival date, with
|
||||
the month zero-padded). A successfully parsed report whose archive
|
||||
date can't be determined is left in place with a logged warning.
|
||||
Files that fail to parse as a report are moved to
|
||||
`<archive_directory>/Invalid/`; files that fail for other reasons,
|
||||
such as transient I/O errors, are left in place so a later run can
|
||||
retry them. An existing destination file is never overwritten; a
|
||||
numeric suffix is appended before the extension (e.g.
|
||||
`report-1.xml`). This applies only to direct local file input —
|
||||
reports fetched from mailboxes (IMAP, Microsoft Graph, Gmail API,
|
||||
Maildir) use `[mailbox] archive_folder` instead, and mbox files are
|
||||
never moved. Files already inside `archive_directory` are excluded
|
||||
from processing, so the archive may safely live inside an input
|
||||
directory. A failed move is logged and does not stop the run.
|
||||
- `aggregate_json_filename` - str: filename for the aggregate
|
||||
JSON output file
|
||||
- `failure_json_filename` - str: filename for the failure
|
||||
@@ -168,21 +186,32 @@ The full set of configuration options are:
|
||||
- `fail_on_output_error` - bool: Exit with a non-zero status code if
|
||||
any configured output destination fails while saving/publishing
|
||||
reports (Default: `False`)
|
||||
|
||||
:::{note}
|
||||
This option only controls the process exit code. Retaining mailbox
|
||||
messages whose reports could not be saved is automatic and happens
|
||||
either way — see
|
||||
[Mailbox messages are only archived once the reports are saved](#mailbox-messages-are-only-archived-once-the-reports-are-saved).
|
||||
:::
|
||||
|
||||
- `log_file` - str: Write log messages to a file at this path
|
||||
- `n_procs` - int: Number of processes to run in parallel when
|
||||
parsing report files passed directly as CLI arguments
|
||||
parsing report files passed directly as CLI arguments, messages
|
||||
in mbox files, and messages from mailbox connections (IMAP,
|
||||
Microsoft Graph, Gmail API, Maildir), including watch mode
|
||||
(Default: `1`)
|
||||
|
||||
:::{note}
|
||||
Setting this to a number larger than one can improve
|
||||
performance when processing thousands of files
|
||||
performance when processing thousands of files or messages
|
||||
:::
|
||||
|
||||
:::{note}
|
||||
`n_procs` only applies to report files passed directly on the
|
||||
command line. Messages from mbox files and from mailbox
|
||||
connections (IMAP, Microsoft Graph, Gmail API, Maildir) are
|
||||
always processed sequentially.
|
||||
Only parsing is parallelized across worker processes. Fetching
|
||||
messages, deduplicating reports, archiving/deleting mailbox
|
||||
messages, and saving/publishing to outputs all stay sequential
|
||||
in the main process. Each worker process keeps its own DNS/GeoIP
|
||||
cache.
|
||||
:::
|
||||
|
||||
- `mailbox`
|
||||
@@ -195,12 +224,46 @@ The full set of configuration options are:
|
||||
messages as they arrive or poll MS Graph for new messages
|
||||
- `delete` - bool: Delete messages after processing them,
|
||||
instead of archiving them
|
||||
- `delete_aggregate` - bool: Delete aggregate report messages
|
||||
after processing them, instead of archiving them
|
||||
(Default: the value of `delete`)
|
||||
- `delete_failure` - bool: Delete failure report messages
|
||||
after processing them, instead of archiving them
|
||||
(Default: the value of `delete`)
|
||||
- `delete_smtp_tls` - bool: Delete SMTP TLS report messages
|
||||
after processing them, instead of archiving them
|
||||
(Default: the value of `delete`)
|
||||
- `delete_invalid` - bool: Delete messages that could not be
|
||||
parsed, instead of archiving them in the `Invalid`
|
||||
subfolder, where they can be inspected for debugging
|
||||
(Default: the value of `delete`)
|
||||
|
||||
:::{note}
|
||||
Each of these four options overrides `delete` for one kind of
|
||||
message only, and the other three keep inheriting `delete`. So
|
||||
`delete = True` combined with `delete_failure = False` archives
|
||||
failure report messages while deleting processed aggregate and
|
||||
SMTP TLS report messages — and unparseable ones, unless
|
||||
`delete_invalid = False` is set as well.
|
||||
:::
|
||||
|
||||
- `test` - bool: Do not move or delete messages
|
||||
- `batch_size` - int: Number of messages to read and process
|
||||
before saving. Default `10`. Use `0` for no limit.
|
||||
- `check_timeout` - int: Number of seconds to wait for a IMAP
|
||||
- `check_timeout` - int: Number of seconds to wait for an IMAP
|
||||
IDLE response or the number of seconds until the next
|
||||
mail check (Default: `30`)
|
||||
- `max_unsaved_retries` - int: How many times a batch of messages
|
||||
whose reports could not be saved is retried before its messages
|
||||
are moved to the `Unsaved` archive subfolder instead of being
|
||||
retried again (Default: `2`, i.e. the initial attempt plus two
|
||||
retries). Use `0` to move messages on the first failed save;
|
||||
negative values are rejected.
|
||||
Failures are counted in memory, so the cap applies across watch-mode
|
||||
checks within one long-running process, not across separate one-shot
|
||||
runs. See
|
||||
[Mailbox messages are only archived once the reports are saved](#mailbox-messages-are-only-archived-once-the-reports-are-saved)
|
||||
below.
|
||||
- `since` - str: Search for messages since certain time. (Examples: `5m|3h|2d|1w`)
|
||||
Acceptable units - {"m":"minutes", "h":"hours", "d":"days", "w":"weeks"}.
|
||||
Defaults to `1d` if incorrect value is provided.
|
||||
@@ -806,6 +869,78 @@ PUT _cluster/settings
|
||||
Increasing this value increases resource usage.
|
||||
:::
|
||||
|
||||
### Mailbox messages are only archived once the reports are saved
|
||||
|
||||
parsedmarc processes a mailbox in batches of `batch_size` messages. Each
|
||||
batch is written to every configured output destination *before* any of
|
||||
that batch's messages are archived or deleted. If any destination reports a
|
||||
failure — an Elasticsearch outage, an expired Splunk HEC token, an
|
||||
unreachable Kafka broker, a full `--output` disk — the whole batch is left
|
||||
in the reports folder and retried on the next run or watch-mode check, so a
|
||||
report is never removed from the mailbox while it exists nowhere else
|
||||
([issue #242](https://github.com/domainaware/parsedmarc/issues/242)).
|
||||
|
||||
This is all-or-nothing per batch: archiving a batch because most
|
||||
destinations accepted it would still permanently lose the data for the one
|
||||
that didn't. It also applies regardless of `fail_on_output_error`, which
|
||||
only controls the process exit code. Messages that could not be parsed at
|
||||
all carry no report data, so they are filed under `Invalid` (or deleted per
|
||||
`delete_invalid`) as usual.
|
||||
|
||||
A destination that is broken rather than briefly unavailable would
|
||||
otherwise be retried forever, so retries are capped. Once a message's batch
|
||||
has failed `max_unsaved_retries + 1` times (three times by default), that
|
||||
message is moved to `<archive_folder>/Unsaved` and stops being retried. **A
|
||||
message is never deleted on this path, whatever the `delete` options say.**
|
||||
To recover after fixing the output destination, either move the messages
|
||||
from `Archive/Unsaved` back into the reports folder, or run parsedmarc once
|
||||
with `reports_folder = Archive/Unsaved`.
|
||||
|
||||
:::{note}
|
||||
The failure counts live in memory, so they are counted per parsedmarc
|
||||
process. In watch mode — a long-running process that checks the mailbox
|
||||
repeatedly — the cap works as described across checks. A one-shot run
|
||||
(`cron`, `systemd` timers) attempts each message exactly once and then
|
||||
exits, so its counts start over every time and the default cap is never
|
||||
reached: messages simply keep being retried on every run, which is the
|
||||
safe direction. Set `max_unsaved_retries = 0` if you want one-shot runs to
|
||||
move unsavable messages to `Unsaved` immediately instead.
|
||||
:::
|
||||
|
||||
:::{warning}
|
||||
Retrying a batch means re-sending it. Output destinations that
|
||||
deduplicate — Elasticsearch, OpenSearch, and PostgreSQL, which recognize
|
||||
an already-saved report — are unaffected, and S3 is idempotent because
|
||||
each report is written to an object key built from its type, date, and
|
||||
report ID, so a retry overwrites the same object. Kafka,
|
||||
Splunk HEC, syslog, GELF, webhooks, Azure Log Analytics, and the
|
||||
`--output` JSON/CSV files all append unconditionally, so each retry adds
|
||||
another copy of every report in the batch. That is why the default retry
|
||||
cap is deliberately low: at most three deliveries per report before its
|
||||
message is set aside in `Unsaved`. The summary email covers everything
|
||||
parsed in a run, including reports whose batch failed to save, so a report
|
||||
retried across runs can also appear in more than one summary email.
|
||||
:::
|
||||
|
||||
:::{note}
|
||||
Not every destination can report a failed delivery. The webhook output
|
||||
deliberately logs and swallows its own HTTP and network errors, and the
|
||||
syslog and GELF outputs send through Python logging handlers, which
|
||||
swallow delivery errors by design — so an unreachable webhook, syslog, or
|
||||
GELF endpoint is *not* treated as a failed save and does not hold a
|
||||
batch's messages back. Failures in Elasticsearch, OpenSearch, Splunk HEC,
|
||||
Kafka, S3, PostgreSQL, Azure Log Analytics, and the `--output` files are
|
||||
all detected and do.
|
||||
:::
|
||||
|
||||
:::{note}
|
||||
`since` interacts with retries: a message that ages out of the configured
|
||||
`since` window stops being fetched, and therefore stops being retried
|
||||
automatically. It is never deleted or moved — it simply stays in the
|
||||
reports folder until it is processed by a run with a wider (or no)
|
||||
`since` window.
|
||||
:::
|
||||
|
||||
## Environment variable configuration
|
||||
|
||||
Any configuration option can be set via environment variables using the
|
||||
@@ -941,6 +1076,50 @@ For sections with underscores in the name, the full section name is used:
|
||||
| `gelf` | `PARSEDMARC_GELF_` |
|
||||
| `webhook` | `PARSEDMARC_WEBHOOK_` |
|
||||
|
||||
## Using parsedmarc as a library
|
||||
|
||||
`parsedmarc` is also importable as a regular Python package, not just a CLI
|
||||
tool. The main entry points — `parse_report_file()`, `parse_aggregate_report_xml()`,
|
||||
`parse_aggregate_report_file()`, `parse_failure_report()`, `parse_report_email()`,
|
||||
`get_dmarc_reports_from_mbox()`, `get_dmarc_reports_from_mailbox()`, and
|
||||
`watch_inbox()` — are all importable
|
||||
directly from the `parsedmarc` package. See the [API reference](api.md) for
|
||||
the full set of modules and members.
|
||||
|
||||
Each of these functions accepts either individual option keyword arguments
|
||||
(`offline`, `nameservers`, `dns_timeout`, etc.) or a single `config=` keyword
|
||||
argument carrying a `ParserConfig` instance:
|
||||
|
||||
```python
|
||||
from parsedmarc import ParserConfig, parse_report_file, get_dmarc_reports_from_mailbox
|
||||
from parsedmarc.mail import IMAPConnection
|
||||
|
||||
config = ParserConfig(
|
||||
offline=False,
|
||||
nameservers=["1.1.1.1", "1.0.0.1"],
|
||||
dns_timeout=5.0,
|
||||
)
|
||||
|
||||
report = parse_report_file("aggregate_report.xml.gz", config=config)
|
||||
|
||||
connection = IMAPConnection(
|
||||
host="imap.example.com", user="dmarc@example.com", password="..."
|
||||
)
|
||||
results = get_dmarc_reports_from_mailbox(connection, config=config)
|
||||
```
|
||||
|
||||
A few things to keep in mind:
|
||||
|
||||
- When `config=` is passed, the individual option keyword arguments are
|
||||
ignored in favor of the values carried on the `ParserConfig` instance.
|
||||
- Each explicitly constructed `ParserConfig` owns its own isolated caches
|
||||
(IP address info, seen aggregate report IDs, and the reverse DNS map).
|
||||
Omitting `config=` falls back to the process-wide caches shared by every
|
||||
call that doesn't pass one.
|
||||
- `keep_alive` and `n_procs` are not part of `ParserConfig` — they control
|
||||
process/worker orchestration rather than parsing or enrichment behavior,
|
||||
so they are always passed as separate keyword arguments.
|
||||
|
||||
## Performance tuning
|
||||
|
||||
For large mailbox imports or backfills, parsedmarc can consume a noticeable amount
|
||||
@@ -951,8 +1130,12 @@ imports more predictable:
|
||||
- Reduce `mailbox.batch_size` to smaller values such as `100-500` instead of
|
||||
processing a very large message set at once. Smaller batches trade throughput
|
||||
for lower peak memory use and less sink pressure.
|
||||
- Keep `n_procs` low for mailbox-heavy runs. In practice, `1-2` workers is often
|
||||
a safer starting point for large backfills than aggressive parallelism.
|
||||
- `n_procs` now parallelizes parsing for mailbox and mbox runs too, not just
|
||||
report files passed directly as CLI arguments. It pays off most when a run
|
||||
is bound by DNS/GeoIP enrichment rather than fetching or output. The
|
||||
trade-off is memory and DNS load: at most roughly `2 * n_procs` messages
|
||||
are held in flight at once, each worker process keeps its own DNS/GeoIP
|
||||
cache, and DNS query volume can multiply by up to `n_procs`.
|
||||
- Use `mailbox.since` to process reports in smaller time windows such as `1d`,
|
||||
`7d`, or another interval that fits the backlog. This makes it easier to catch
|
||||
up incrementally instead of loading an entire mailbox history in one run.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const DOCUMENTATION_OPTIONS = {
|
||||
VERSION: '10.3.0',
|
||||
VERSION: '10.4.0',
|
||||
LANGUAGE: 'en',
|
||||
COLLAPSE_INDEX: false,
|
||||
BUILDER: 'html',
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Contributing to parsedmarc — parsedmarc 10.3.0 documentation</title>
|
||||
<title>Contributing to parsedmarc — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Accessing an inbox using OWA/EWS — parsedmarc 10.3.0 documentation</title>
|
||||
<title>Accessing an inbox using OWA/EWS — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Understanding DMARC — parsedmarc 10.3.0 documentation</title>
|
||||
<title>Understanding DMARC — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Elasticsearch and Kibana — parsedmarc 10.3.0 documentation</title>
|
||||
<title>Elasticsearch and Kibana — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+61
-7
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Index — parsedmarc 10.3.0 documentation</title>
|
||||
<title>Index — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
@@ -91,6 +91,7 @@
|
||||
| <a href="#I"><strong>I</strong></a>
|
||||
| <a href="#L"><strong>L</strong></a>
|
||||
| <a href="#M"><strong>M</strong></a>
|
||||
| <a href="#N"><strong>N</strong></a>
|
||||
| <a href="#O"><strong>O</strong></a>
|
||||
| <a href="#P"><strong>P</strong></a>
|
||||
| <a href="#Q"><strong>Q</strong></a>
|
||||
@@ -130,6 +131,8 @@
|
||||
<li><a href="api.html#parsedmarc.types.AggregateReportMetadata">AggregateReportMetadata (class in parsedmarc.types)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.elastic.AlreadySaved">AlreadySaved</a>, <a href="api.html#parsedmarc.opensearch.AlreadySaved">[1]</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig.always_use_local_files">always_use_local_files (parsedmarc.config.ParserConfig attribute)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.append_json">append_json() (in module parsedmarc)</a>
|
||||
</li>
|
||||
@@ -160,9 +163,13 @@
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="api.html#parsedmarc.utils.decode_base64">decode_base64() (in module parsedmarc.utils)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig.dns_retries">dns_retries (parsedmarc.config.ParserConfig attribute)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig.dns_timeout">dns_timeout (parsedmarc.config.ParserConfig attribute)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.utils.DownloadError">DownloadError</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
@@ -262,10 +269,14 @@
|
||||
<li><a href="api.html#parsedmarc.InvalidForensicReport">InvalidForensicReport (in module parsedmarc)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.utils.InvalidIPinfoAPIKey">InvalidIPinfoAPIKey</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.InvalidSMTPTLSReport">InvalidSMTPTLSReport</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="api.html#parsedmarc.InvalidSMTPTLSReport">InvalidSMTPTLSReport</a>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig.ip_address_cache">ip_address_cache (parsedmarc.config.ParserConfig attribute)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig.ip_db_path">ip_db_path (parsedmarc.config.ParserConfig attribute)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.utils.IPAddressInfo">IPAddressInfo (class in parsedmarc.utils)</a>
|
||||
</li>
|
||||
@@ -306,6 +317,8 @@
|
||||
|
||||
<ul>
|
||||
<li><a href="api.html#module-parsedmarc">parsedmarc</a>
|
||||
</li>
|
||||
<li><a href="api.html#module-parsedmarc.config">parsedmarc.config</a>
|
||||
</li>
|
||||
<li><a href="api.html#module-parsedmarc.elastic">parsedmarc.elastic</a>
|
||||
</li>
|
||||
@@ -321,8 +334,24 @@
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
|
||||
<h2 id="N">N</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig.nameservers">nameservers (parsedmarc.config.ParserConfig attribute)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig.normalize_timespan_threshold_hours">normalize_timespan_threshold_hours (parsedmarc.config.ParserConfig attribute)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
|
||||
<h2 id="O">O</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig.offline">offline (parsedmarc.config.ParserConfig attribute)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="api.html#parsedmarc.opensearch.OpenSearchError">OpenSearchError</a>
|
||||
</li>
|
||||
@@ -362,8 +391,6 @@
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.parsed_smtp_tls_reports_to_csv">parsed_smtp_tls_reports_to_csv() (in module parsedmarc)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="api.html#parsedmarc.parsed_smtp_tls_reports_to_csv_rows">parsed_smtp_tls_reports_to_csv_rows() (in module parsedmarc)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.types.ParsedEmail">ParsedEmail (class in parsedmarc.types)</a>
|
||||
@@ -373,6 +400,15 @@
|
||||
|
||||
<ul>
|
||||
<li><a href="api.html#module-parsedmarc">module</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li>
|
||||
parsedmarc.config
|
||||
|
||||
<ul>
|
||||
<li><a href="api.html#module-parsedmarc.config">module</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
@@ -410,9 +446,15 @@
|
||||
<li><a href="api.html#module-parsedmarc.utils">module</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig">ParserConfig (class in parsedmarc.config)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.ParserError">ParserError</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.types.ParsingResults">ParsingResults (class in parsedmarc.types)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig.psl_overrides_path">psl_overrides_path (parsedmarc.config.ParserConfig attribute)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig.psl_overrides_url">psl_overrides_url (parsedmarc.config.ParserConfig attribute)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@@ -428,6 +470,14 @@
|
||||
<h2 id="R">R</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig.reverse_dns_map">reverse_dns_map (parsedmarc.config.ParserConfig attribute)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig.reverse_dns_map_path">reverse_dns_map_path (parsedmarc.config.ParserConfig attribute)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig.reverse_dns_map_url">reverse_dns_map_url (parsedmarc.config.ParserConfig attribute)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.utils.ReverseDNSService">ReverseDNSService (class in parsedmarc.utils)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
@@ -458,11 +508,13 @@
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.elastic.save_smtp_tls_report_to_elasticsearch">save_smtp_tls_report_to_elasticsearch() (in module parsedmarc.elastic)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="api.html#parsedmarc.opensearch.save_smtp_tls_report_to_opensearch">save_smtp_tls_report_to_opensearch() (in module parsedmarc.opensearch)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="api.html#parsedmarc.splunk.HECClient.save_smtp_tls_reports_to_splunk">save_smtp_tls_reports_to_splunk() (parsedmarc.splunk.HECClient method)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig.seen_aggregate_report_ids">seen_aggregate_report_ids (parsedmarc.config.ParserConfig attribute)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.elastic.set_hosts">set_hosts() (in module parsedmarc.elastic)</a>
|
||||
|
||||
@@ -483,6 +535,8 @@
|
||||
<li><a href="api.html#parsedmarc.types.SMTPTLSReport">SMTPTLSReport (class in parsedmarc.types)</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.splunk.SplunkError">SplunkError</a>
|
||||
</li>
|
||||
<li><a href="api.html#parsedmarc.config.ParserConfig.strip_attachment_payloads">strip_attachment_payloads (parsedmarc.config.ParserConfig attribute)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
|
||||
+4
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>parsedmarc documentation - Open source DMARC report analyzer and visualizer — parsedmarc 10.3.0 documentation</title>
|
||||
<title>parsedmarc documentation - Open source DMARC report analyzer and visualizer — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
@@ -187,6 +187,7 @@ for RHEL or Debian.</p>
|
||||
<li class="toctree-l2"><a class="reference internal" href="usage.html#cli-help">CLI help</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="usage.html#configuration-file">Configuration file</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="usage.html#environment-variable-configuration">Environment variable configuration</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="usage.html#using-parsedmarc-as-a-library">Using parsedmarc as a library</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="usage.html#performance-tuning">Performance tuning</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="usage.html#multi-tenant-support">Multi-tenant support</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="usage.html#running-parsedmarc-as-a-systemd-service">Running parsedmarc as a systemd service</a></li>
|
||||
@@ -234,6 +235,7 @@ for RHEL or Debian.</p>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="api.html">API reference</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="api.html#module-parsedmarc">parsedmarc</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="api.html#module-parsedmarc.config">parsedmarc.config</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="api.html#module-parsedmarc.elastic">parsedmarc.elastic</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="api.html#module-parsedmarc.opensearch">parsedmarc.opensearch</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="api.html#module-parsedmarc.splunk">parsedmarc.splunk</a></li>
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Installation — parsedmarc 10.3.0 documentation</title>
|
||||
<title>Installation — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+3
-3
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Using the Kibana dashboards — parsedmarc 10.3.0 documentation</title>
|
||||
<title>Using the Kibana dashboards — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
@@ -120,7 +120,7 @@ passes if a message passes SPF or DKIM alignment, only DKIM alignment remains
|
||||
valid when a message is forwarded without changing the from address, which is
|
||||
often caused by a mailbox forwarding rule. This is because DKIM signatures are
|
||||
part of the message headers, whereas SPF relies on SMTP session headers.</p>
|
||||
<p>Underneath the pie charts. you can see graphs of DMARC passage and message
|
||||
<p>Underneath the pie charts, you can see graphs of DMARC compliance and message
|
||||
disposition over time.</p>
|
||||
<p>Under the graphs you will find the most useful data tables on the dashboard. On
|
||||
the left, there is a list of organizations that are sending you DMARC reports.
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>What about mailing lists? — parsedmarc 10.3.0 documentation</title>
|
||||
<title>What about mailing lists? — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
BIN
Binary file not shown.
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>OpenSearch and Grafana — parsedmarc 10.3.0 documentation</title>
|
||||
<title>OpenSearch and Grafana — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Sample outputs — parsedmarc 10.3.0 documentation</title>
|
||||
<title>Sample outputs — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+7
-2
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Python Module Index — parsedmarc 10.3.0 documentation</title>
|
||||
<title>Python Module Index — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
@@ -97,6 +97,11 @@
|
||||
<td>
|
||||
<a href="api.html#module-parsedmarc"><code class="xref">parsedmarc</code></a></td><td>
|
||||
<em></em></td></tr>
|
||||
<tr class="cg-1">
|
||||
<td></td>
|
||||
<td>   
|
||||
<a href="api.html#module-parsedmarc.config"><code class="xref">parsedmarc.config</code></a></td><td>
|
||||
<em></em></td></tr>
|
||||
<tr class="cg-1">
|
||||
<td></td>
|
||||
<td>   
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Search — parsedmarc 10.3.0 documentation</title>
|
||||
<title>Search — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+3
-3
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Splunk — parsedmarc 10.3.0 documentation</title>
|
||||
<title>Splunk — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
@@ -85,7 +85,7 @@
|
||||
<h1>Splunk<a class="headerlink" href="#splunk" title="Link to this heading"></a></h1>
|
||||
<p>Starting in version 4.3.0 <code class="docutils literal notranslate"><span class="pre">parsedmarc</span></code> supports sending aggregate and/or
|
||||
failure DMARC data to a Splunk <a class="reference external" href="http://docs.splunk.com/Documentation/Splunk/latest/Data/AboutHEC">HTTP Event collector (HEC)</a>.</p>
|
||||
<p>The project repository contains <a class="reference external" href="https://github.com/domainaware/parsedmarc/tree/master/splunk">XML files</a> for premade Splunk
|
||||
<p>The project repository contains <a class="reference external" href="https://github.com/domainaware/parsedmarc/tree/master/dashboards/splunk">XML files</a> for premade Splunk
|
||||
dashboards for aggregate and failure DMARC reports.</p>
|
||||
<p>Copy and paste the contents of each file into a separate Splunk
|
||||
dashboard XML editor.</p>
|
||||
|
||||
+197
-14
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Using parsedmarc — parsedmarc 10.3.0 documentation</title>
|
||||
<title>Using parsedmarc — parsedmarc 10.4.0 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=9edc463e" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=a126560f"></script>
|
||||
<script src="_static/documentation_options.js?v=2f7da7c1"></script>
|
||||
<script src="_static/doctools.js?v=fd6eb6e6"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
@@ -47,7 +47,10 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li>
|
||||
<li class="toctree-l1 current"><a class="current reference internal" href="#">Using parsedmarc</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#cli-help">CLI help</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#configuration-file">Configuration file</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#configuration-file">Configuration file</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="#mailbox-messages-are-only-archived-once-the-reports-are-saved">Mailbox messages are only archived once the reports are saved</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#environment-variable-configuration">Environment variable configuration</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="#examples">Examples</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="#specifying-the-config-file-via-environment-variable">Specifying the config file via environment variable</a></li>
|
||||
@@ -57,6 +60,7 @@
|
||||
<li class="toctree-l3"><a class="reference internal" href="#section-name-mapping">Section name mapping</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#using-parsedmarc-as-a-library">Using parsedmarc as a library</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#performance-tuning">Performance tuning</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#multi-tenant-support">Multi-tenant support</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#running-parsedmarc-as-a-systemd-service">Running parsedmarc as a systemd service</a><ul>
|
||||
@@ -231,6 +235,24 @@ Elasticsearch, Splunk and/or S3</p></li>
|
||||
payloads from results</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">silent</span></code> - bool: Set this to <code class="docutils literal notranslate"><span class="pre">False</span></code> to output results to STDOUT</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">output</span></code> - str: Directory to place JSON and CSV files in. This is required if you set either of the JSON output file options.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">archive_directory</span></code> - str: Optional. When set, successfully
|
||||
processed report files given as local file/directory path
|
||||
arguments are moved into
|
||||
<code class="docutils literal notranslate"><span class="pre"><archive_directory>/<year>/<month>/<Aggregate|Failure|SMTP-TLS>/</span></code>
|
||||
(year and month come from the report’s own begin/arrival date, with
|
||||
the month zero-padded). A successfully parsed report whose archive
|
||||
date can’t be determined is left in place with a logged warning.
|
||||
Files that fail to parse as a report are moved to
|
||||
<code class="docutils literal notranslate"><span class="pre"><archive_directory>/Invalid/</span></code>; files that fail for other reasons,
|
||||
such as transient I/O errors, are left in place so a later run can
|
||||
retry them. An existing destination file is never overwritten; a
|
||||
numeric suffix is appended before the extension (e.g.
|
||||
<code class="docutils literal notranslate"><span class="pre">report-1.xml</span></code>). This applies only to direct local file input —
|
||||
reports fetched from mailboxes (IMAP, Microsoft Graph, Gmail API,
|
||||
Maildir) use <code class="docutils literal notranslate"><span class="pre">[mailbox]</span> <span class="pre">archive_folder</span></code> instead, and mbox files are
|
||||
never moved. Files already inside <code class="docutils literal notranslate"><span class="pre">archive_directory</span></code> are excluded
|
||||
from processing, so the archive may safely live inside an input
|
||||
directory. A failed move is logged and does not stop the run.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">aggregate_json_filename</span></code> - str: filename for the aggregate
|
||||
JSON output file</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">failure_json_filename</span></code> - str: filename for the failure
|
||||
@@ -266,28 +288,39 @@ DNS resolvers (Default: <code class="docutils literal notranslate"><span class="
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">silent</span></code> - bool: Only print errors (Default: <code class="docutils literal notranslate"><span class="pre">True</span></code>)</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">fail_on_output_error</span></code> - bool: Exit with a non-zero status code if
|
||||
any configured output destination fails while saving/publishing
|
||||
reports (Default: <code class="docutils literal notranslate"><span class="pre">False</span></code>)</p></li>
|
||||
reports (Default: <code class="docutils literal notranslate"><span class="pre">False</span></code>)</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>This option only controls the process exit code. Retaining mailbox
|
||||
messages whose reports could not be saved is automatic and happens
|
||||
either way — see
|
||||
<a class="reference internal" href="#mailbox-messages-are-only-archived-once-the-reports-are-saved">Mailbox messages are only archived once the reports are saved</a>.</p>
|
||||
</div>
|
||||
</li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">log_file</span></code> - str: Write log messages to a file at this path</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">n_procs</span></code> - int: Number of processes to run in parallel when
|
||||
parsing report files passed directly as CLI arguments
|
||||
parsing report files passed directly as CLI arguments, messages
|
||||
in mbox files, and messages from mailbox connections (IMAP,
|
||||
Microsoft Graph, Gmail API, Maildir), including watch mode
|
||||
(Default: <code class="docutils literal notranslate"><span class="pre">1</span></code>)</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>Setting this to a number larger than one can improve
|
||||
performance when processing thousands of files</p>
|
||||
performance when processing thousands of files or messages</p>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">n_procs</span></code> only applies to report files passed directly on the
|
||||
command line. Messages from mbox files and from mailbox
|
||||
connections (IMAP, Microsoft Graph, Gmail API, Maildir) are
|
||||
always processed sequentially.</p>
|
||||
<p>Only parsing is parallelized across worker processes. Fetching
|
||||
messages, deduplicating reports, archiving/deleting mailbox
|
||||
messages, and saving/publishing to outputs all stay sequential
|
||||
in the main process. Each worker process keeps its own DNS/GeoIP
|
||||
cache.</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">mailbox</span></code></p>
|
||||
<ul class="simple">
|
||||
<ul>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">reports_folder</span></code> - str: The mailbox folder (or label for
|
||||
Gmail) where the incoming reports can be found
|
||||
(Default: <code class="docutils literal notranslate"><span class="pre">INBOX</span></code>)</p></li>
|
||||
@@ -297,12 +330,46 @@ Gmail) to sort processed emails into (Default: <code class="docutils literal not
|
||||
messages as they arrive or poll MS Graph for new messages</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">delete</span></code> - bool: Delete messages after processing them,
|
||||
instead of archiving them</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">delete_aggregate</span></code> - bool: Delete aggregate report messages
|
||||
after processing them, instead of archiving them
|
||||
(Default: the value of <code class="docutils literal notranslate"><span class="pre">delete</span></code>)</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">delete_failure</span></code> - bool: Delete failure report messages
|
||||
after processing them, instead of archiving them
|
||||
(Default: the value of <code class="docutils literal notranslate"><span class="pre">delete</span></code>)</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">delete_smtp_tls</span></code> - bool: Delete SMTP TLS report messages
|
||||
after processing them, instead of archiving them
|
||||
(Default: the value of <code class="docutils literal notranslate"><span class="pre">delete</span></code>)</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">delete_invalid</span></code> - bool: Delete messages that could not be
|
||||
parsed, instead of archiving them in the <code class="docutils literal notranslate"><span class="pre">Invalid</span></code>
|
||||
subfolder, where they can be inspected for debugging
|
||||
(Default: the value of <code class="docutils literal notranslate"><span class="pre">delete</span></code>)</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>Each of these four options overrides <code class="docutils literal notranslate"><span class="pre">delete</span></code> for one kind of
|
||||
message only, and the other three keep inheriting <code class="docutils literal notranslate"><span class="pre">delete</span></code>. So
|
||||
<code class="docutils literal notranslate"><span class="pre">delete</span> <span class="pre">=</span> <span class="pre">True</span></code> combined with <code class="docutils literal notranslate"><span class="pre">delete_failure</span> <span class="pre">=</span> <span class="pre">False</span></code> archives
|
||||
failure report messages while deleting processed aggregate and
|
||||
SMTP TLS report messages — and unparseable ones, unless
|
||||
<code class="docutils literal notranslate"><span class="pre">delete_invalid</span> <span class="pre">=</span> <span class="pre">False</span></code> is set as well.</p>
|
||||
</div>
|
||||
</li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">test</span></code> - bool: Do not move or delete messages</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">batch_size</span></code> - int: Number of messages to read and process
|
||||
before saving. Default <code class="docutils literal notranslate"><span class="pre">10</span></code>. Use <code class="docutils literal notranslate"><span class="pre">0</span></code> for no limit.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">check_timeout</span></code> - int: Number of seconds to wait for a IMAP
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">check_timeout</span></code> - int: Number of seconds to wait for an IMAP
|
||||
IDLE response or the number of seconds until the next
|
||||
mail check (Default: <code class="docutils literal notranslate"><span class="pre">30</span></code>)</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">max_unsaved_retries</span></code> - int: How many times a batch of messages
|
||||
whose reports could not be saved is retried before its messages
|
||||
are moved to the <code class="docutils literal notranslate"><span class="pre">Unsaved</span></code> archive subfolder instead of being
|
||||
retried again (Default: <code class="docutils literal notranslate"><span class="pre">2</span></code>, i.e. the initial attempt plus two
|
||||
retries). Use <code class="docutils literal notranslate"><span class="pre">0</span></code> to move messages on the first failed save;
|
||||
negative values are rejected.
|
||||
Failures are counted in memory, so the cap applies across watch-mode
|
||||
checks within one long-running process, not across separate one-shot
|
||||
runs. See
|
||||
<a class="reference internal" href="#mailbox-messages-are-only-archived-once-the-reports-are-saved">Mailbox messages are only archived once the reports are saved</a>
|
||||
below.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">since</span></code> - str: Search for messages since certain time. (Examples: <code class="docutils literal notranslate"><span class="pre">5m|3h|2d|1w</span></code>)
|
||||
Acceptable units - {“m”:“minutes”, “h”:“hours”, “d”:“days”, “w”:“weeks”}.
|
||||
Defaults to <code class="docutils literal notranslate"><span class="pre">1d</span></code> if incorrect value is provided.</p></li>
|
||||
@@ -986,6 +1053,76 @@ Check current usage (from Management -> Dev Tools -> Console):</p>
|
||||
</div>
|
||||
<p>Increasing this value increases resource usage.</p>
|
||||
</div>
|
||||
<section id="mailbox-messages-are-only-archived-once-the-reports-are-saved">
|
||||
<h3>Mailbox messages are only archived once the reports are saved<a class="headerlink" href="#mailbox-messages-are-only-archived-once-the-reports-are-saved" title="Link to this heading"></a></h3>
|
||||
<p>parsedmarc processes a mailbox in batches of <code class="docutils literal notranslate"><span class="pre">batch_size</span></code> messages. Each
|
||||
batch is written to every configured output destination <em>before</em> any of
|
||||
that batch’s messages are archived or deleted. If any destination reports a
|
||||
failure — an Elasticsearch outage, an expired Splunk HEC token, an
|
||||
unreachable Kafka broker, a full <code class="docutils literal notranslate"><span class="pre">--output</span></code> disk — the whole batch is left
|
||||
in the reports folder and retried on the next run or watch-mode check, so a
|
||||
report is never removed from the mailbox while it exists nowhere else
|
||||
(<a class="reference external" href="https://github.com/domainaware/parsedmarc/issues/242">issue #242</a>).</p>
|
||||
<p>This is all-or-nothing per batch: archiving a batch because most
|
||||
destinations accepted it would still permanently lose the data for the one
|
||||
that didn’t. It also applies regardless of <code class="docutils literal notranslate"><span class="pre">fail_on_output_error</span></code>, which
|
||||
only controls the process exit code. Messages that could not be parsed at
|
||||
all carry no report data, so they are filed under <code class="docutils literal notranslate"><span class="pre">Invalid</span></code> (or deleted per
|
||||
<code class="docutils literal notranslate"><span class="pre">delete_invalid</span></code>) as usual.</p>
|
||||
<p>A destination that is broken rather than briefly unavailable would
|
||||
otherwise be retried forever, so retries are capped. Once a message’s batch
|
||||
has failed <code class="docutils literal notranslate"><span class="pre">max_unsaved_retries</span> <span class="pre">+</span> <span class="pre">1</span></code> times (three times by default), that
|
||||
message is moved to <code class="docutils literal notranslate"><span class="pre"><archive_folder>/Unsaved</span></code> and stops being retried. <strong>A
|
||||
message is never deleted on this path, whatever the <code class="docutils literal notranslate"><span class="pre">delete</span></code> options say.</strong>
|
||||
To recover after fixing the output destination, either move the messages
|
||||
from <code class="docutils literal notranslate"><span class="pre">Archive/Unsaved</span></code> back into the reports folder, or run parsedmarc once
|
||||
with <code class="docutils literal notranslate"><span class="pre">reports_folder</span> <span class="pre">=</span> <span class="pre">Archive/Unsaved</span></code>.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>The failure counts live in memory, so they are counted per parsedmarc
|
||||
process. In watch mode — a long-running process that checks the mailbox
|
||||
repeatedly — the cap works as described across checks. A one-shot run
|
||||
(<code class="docutils literal notranslate"><span class="pre">cron</span></code>, <code class="docutils literal notranslate"><span class="pre">systemd</span></code> timers) attempts each message exactly once and then
|
||||
exits, so its counts start over every time and the default cap is never
|
||||
reached: messages simply keep being retried on every run, which is the
|
||||
safe direction. Set <code class="docutils literal notranslate"><span class="pre">max_unsaved_retries</span> <span class="pre">=</span> <span class="pre">0</span></code> if you want one-shot runs to
|
||||
move unsavable messages to <code class="docutils literal notranslate"><span class="pre">Unsaved</span></code> immediately instead.</p>
|
||||
</div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>Retrying a batch means re-sending it. Output destinations that
|
||||
deduplicate — Elasticsearch, OpenSearch, and PostgreSQL, which recognize
|
||||
an already-saved report — are unaffected, and S3 is idempotent because
|
||||
each report is written to an object key built from its type, date, and
|
||||
report ID, so a retry overwrites the same object. Kafka,
|
||||
Splunk HEC, syslog, GELF, webhooks, Azure Log Analytics, and the
|
||||
<code class="docutils literal notranslate"><span class="pre">--output</span></code> JSON/CSV files all append unconditionally, so each retry adds
|
||||
another copy of every report in the batch. That is why the default retry
|
||||
cap is deliberately low: at most three deliveries per report before its
|
||||
message is set aside in <code class="docutils literal notranslate"><span class="pre">Unsaved</span></code>. The summary email covers everything
|
||||
parsed in a run, including reports whose batch failed to save, so a report
|
||||
retried across runs can also appear in more than one summary email.</p>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>Not every destination can report a failed delivery. The webhook output
|
||||
deliberately logs and swallows its own HTTP and network errors, and the
|
||||
syslog and GELF outputs send through Python logging handlers, which
|
||||
swallow delivery errors by design — so an unreachable webhook, syslog, or
|
||||
GELF endpoint is <em>not</em> treated as a failed save and does not hold a
|
||||
batch’s messages back. Failures in Elasticsearch, OpenSearch, Splunk HEC,
|
||||
Kafka, S3, PostgreSQL, Azure Log Analytics, and the <code class="docutils literal notranslate"><span class="pre">--output</span></code> files are
|
||||
all detected and do.</p>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">since</span></code> interacts with retries: a message that ages out of the configured
|
||||
<code class="docutils literal notranslate"><span class="pre">since</span></code> window stops being fetched, and therefore stops being retried
|
||||
automatically. It is never deleted or moved — it simply stays in the
|
||||
reports folder until it is processed by a run with a wider (or no)
|
||||
<code class="docutils literal notranslate"><span class="pre">since</span></code> window.</p>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="environment-variable-configuration">
|
||||
<h2>Environment variable configuration<a class="headerlink" href="#environment-variable-configuration" title="Link to this heading"></a></h2>
|
||||
@@ -1154,6 +1291,48 @@ then read and stored as the <code class="docutils literal notranslate"><span cla
|
||||
</table>
|
||||
</section>
|
||||
</section>
|
||||
<section id="using-parsedmarc-as-a-library">
|
||||
<h2>Using parsedmarc as a library<a class="headerlink" href="#using-parsedmarc-as-a-library" title="Link to this heading"></a></h2>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">parsedmarc</span></code> is also importable as a regular Python package, not just a CLI
|
||||
tool. The main entry points — <code class="docutils literal notranslate"><span class="pre">parse_report_file()</span></code>, <code class="docutils literal notranslate"><span class="pre">parse_aggregate_report_xml()</span></code>,
|
||||
<code class="docutils literal notranslate"><span class="pre">parse_aggregate_report_file()</span></code>, <code class="docutils literal notranslate"><span class="pre">parse_failure_report()</span></code>, <code class="docutils literal notranslate"><span class="pre">parse_report_email()</span></code>,
|
||||
<code class="docutils literal notranslate"><span class="pre">get_dmarc_reports_from_mbox()</span></code>, <code class="docutils literal notranslate"><span class="pre">get_dmarc_reports_from_mailbox()</span></code>, and
|
||||
<code class="docutils literal notranslate"><span class="pre">watch_inbox()</span></code> — are all importable
|
||||
directly from the <code class="docutils literal notranslate"><span class="pre">parsedmarc</span></code> package. See the <a class="reference internal" href="api.html"><span class="std std-doc">API reference</span></a> for
|
||||
the full set of modules and members.</p>
|
||||
<p>Each of these functions accepts either individual option keyword arguments
|
||||
(<code class="docutils literal notranslate"><span class="pre">offline</span></code>, <code class="docutils literal notranslate"><span class="pre">nameservers</span></code>, <code class="docutils literal notranslate"><span class="pre">dns_timeout</span></code>, etc.) or a single <code class="docutils literal notranslate"><span class="pre">config=</span></code> keyword
|
||||
argument carrying a <code class="docutils literal notranslate"><span class="pre">ParserConfig</span></code> instance:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">parsedmarc</span><span class="w"> </span><span class="kn">import</span> <span class="n">ParserConfig</span><span class="p">,</span> <span class="n">parse_report_file</span><span class="p">,</span> <span class="n">get_dmarc_reports_from_mailbox</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">parsedmarc.mail</span><span class="w"> </span><span class="kn">import</span> <span class="n">IMAPConnection</span>
|
||||
|
||||
<span class="n">config</span> <span class="o">=</span> <span class="n">ParserConfig</span><span class="p">(</span>
|
||||
<span class="n">offline</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">nameservers</span><span class="o">=</span><span class="p">[</span><span class="s2">"1.1.1.1"</span><span class="p">,</span> <span class="s2">"1.0.0.1"</span><span class="p">],</span>
|
||||
<span class="n">dns_timeout</span><span class="o">=</span><span class="mf">5.0</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="n">report</span> <span class="o">=</span> <span class="n">parse_report_file</span><span class="p">(</span><span class="s2">"aggregate_report.xml.gz"</span><span class="p">,</span> <span class="n">config</span><span class="o">=</span><span class="n">config</span><span class="p">)</span>
|
||||
|
||||
<span class="n">connection</span> <span class="o">=</span> <span class="n">IMAPConnection</span><span class="p">(</span>
|
||||
<span class="n">host</span><span class="o">=</span><span class="s2">"imap.example.com"</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s2">"dmarc@example.com"</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s2">"..."</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">results</span> <span class="o">=</span> <span class="n">get_dmarc_reports_from_mailbox</span><span class="p">(</span><span class="n">connection</span><span class="p">,</span> <span class="n">config</span><span class="o">=</span><span class="n">config</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>A few things to keep in mind:</p>
|
||||
<ul class="simple">
|
||||
<li><p>When <code class="docutils literal notranslate"><span class="pre">config=</span></code> is passed, the individual option keyword arguments are
|
||||
ignored in favor of the values carried on the <code class="docutils literal notranslate"><span class="pre">ParserConfig</span></code> instance.</p></li>
|
||||
<li><p>Each explicitly constructed <code class="docutils literal notranslate"><span class="pre">ParserConfig</span></code> owns its own isolated caches
|
||||
(IP address info, seen aggregate report IDs, and the reverse DNS map).
|
||||
Omitting <code class="docutils literal notranslate"><span class="pre">config=</span></code> falls back to the process-wide caches shared by every
|
||||
call that doesn’t pass one.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">keep_alive</span></code> and <code class="docutils literal notranslate"><span class="pre">n_procs</span></code> are not part of <code class="docutils literal notranslate"><span class="pre">ParserConfig</span></code> — they control
|
||||
process/worker orchestration rather than parsing or enrichment behavior,
|
||||
so they are always passed as separate keyword arguments.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="performance-tuning">
|
||||
<h2>Performance tuning<a class="headerlink" href="#performance-tuning" title="Link to this heading"></a></h2>
|
||||
<p>For large mailbox imports or backfills, parsedmarc can consume a noticeable amount
|
||||
@@ -1164,8 +1343,12 @@ imports more predictable:</p>
|
||||
<li><p>Reduce <code class="docutils literal notranslate"><span class="pre">mailbox.batch_size</span></code> to smaller values such as <code class="docutils literal notranslate"><span class="pre">100-500</span></code> instead of
|
||||
processing a very large message set at once. Smaller batches trade throughput
|
||||
for lower peak memory use and less sink pressure.</p></li>
|
||||
<li><p>Keep <code class="docutils literal notranslate"><span class="pre">n_procs</span></code> low for mailbox-heavy runs. In practice, <code class="docutils literal notranslate"><span class="pre">1-2</span></code> workers is often
|
||||
a safer starting point for large backfills than aggressive parallelism.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">n_procs</span></code> now parallelizes parsing for mailbox and mbox runs too, not just
|
||||
report files passed directly as CLI arguments. It pays off most when a run
|
||||
is bound by DNS/GeoIP enrichment rather than fetching or output. The
|
||||
trade-off is memory and DNS load: at most roughly <code class="docutils literal notranslate"><span class="pre">2</span> <span class="pre">*</span> <span class="pre">n_procs</span></code> messages
|
||||
are held in flight at once, each worker process keeps its own DNS/GeoIP
|
||||
cache, and DNS query volume can multiply by up to <code class="docutils literal notranslate"><span class="pre">n_procs</span></code>.</p></li>
|
||||
<li><p>Use <code class="docutils literal notranslate"><span class="pre">mailbox.since</span></code> to process reports in smaller time windows such as <code class="docutils literal notranslate"><span class="pre">1d</span></code>,
|
||||
<code class="docutils literal notranslate"><span class="pre">7d</span></code>, or another interval that fits the backlog. This makes it easier to catch
|
||||
up incrementally instead of loading an entire mailbox history in one run.</p></li>
|
||||
|
||||
Reference in New Issue
Block a user