Update docs

This commit is contained in:
Sean Whalen
2026-07-20 19:53:46 -04:00
parent 759ea2b815
commit d3dee042cc
28 changed files with 751 additions and 158 deletions
+113 -16
View File
@@ -5,14 +5,14 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>parsedmarc &mdash; parsedmarc 10.2.2 documentation</title>
<title>parsedmarc &mdash; parsedmarc 10.2.4 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=43731225"></script>
<script src="../_static/documentation_options.js?v=2c8206f1"></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>
@@ -1668,6 +1668,27 @@
<span class="n">f</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">parsed_report</span><span class="p">[</span><span class="s2">&quot;auth_failure&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;,&quot;</span><span class="p">)</span> <span class="k">if</span> <span class="n">f</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="p">]</span>
<span class="c1"># Feedback-Type is REQUIRED per RFC 5965 §3.1, but some gateways</span>
<span class="c1"># (e.g. Exim/cPanel-based ones that send a plain-text summary without</span>
<span class="c1"># a machine-readable message/feedback-report part) omit it. The</span>
<span class="c1"># Elasticsearch/OpenSearch outputs require the key, so default it</span>
<span class="c1"># instead of dropping the report there (see issue #332).</span>
<span class="k">if</span> <span class="s2">&quot;feedback_type&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">parsed_report</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
<span class="s2">&quot;Failure report missing required &#39;Feedback-Type&#39; field &quot;</span>
<span class="s2">&quot;(RFC 5965 §3.1); defaulting to &#39;auth-failure&#39;&quot;</span>
<span class="p">)</span>
<span class="n">parsed_report</span><span class="p">[</span><span class="s2">&quot;feedback_type&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;auth-failure&quot;</span>
<span class="c1"># Authentication-Results is likewise REQUIRED per RFC 6591 §3.1 and</span>
<span class="c1"># required by the Elasticsearch/OpenSearch outputs.</span>
<span class="k">if</span> <span class="s2">&quot;authentication_results&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">parsed_report</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
<span class="s2">&quot;Failure report missing required &#39;Authentication-Results&#39; &quot;</span>
<span class="s2">&quot;field (RFC 6591 §3.1); defaulting to None&quot;</span>
<span class="p">)</span>
<span class="n">parsed_report</span><span class="p">[</span><span class="s2">&quot;authentication_results&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">optional_fields</span> <span class="o">=</span> <span class="p">[</span>
<span class="s2">&quot;original_envelope_id&quot;</span><span class="p">,</span>
<span class="s2">&quot;dkim_domain&quot;</span><span class="p">,</span>
@@ -2963,6 +2984,37 @@
<span class="k">def</span><span class="w"> </span><span class="nf">_build_report_email_content</span><span class="p">(</span>
<span class="n">results</span><span class="p">:</span> <span class="n">ParsingResults</span><span class="p">,</span>
<span class="o">*</span><span class="p">,</span>
<span class="n">subject</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">attachment_filename</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">message</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">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="nb">list</span><span class="p">[</span><span class="nb">tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">]]]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Builds the subject, plain-text body, and zip attachment shared by</span>
<span class="sd"> every report-summary email transport.</span>
<span class="sd"> Returns:</span>
<span class="sd"> A ``(subject, plain_message, attachments)`` tuple.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">date_string</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&quot;%Y-%m-</span><span class="si">%d</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">attachment_filename</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">attachment_filename</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">&quot;.zip&quot;</span><span class="p">):</span>
<span class="n">attachment_filename</span> <span class="o">+=</span> <span class="s2">&quot;.zip&quot;</span>
<span class="n">filename</span> <span class="o">=</span> <span class="n">attachment_filename</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">filename</span> <span class="o">=</span> <span class="s2">&quot;DMARC-</span><span class="si">{0}</span><span class="s2">.zip&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">date_string</span><span class="p">)</span>
<span class="k">if</span> <span class="n">subject</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">subject</span> <span class="o">=</span> <span class="s2">&quot;DMARC results for </span><span class="si">{0}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">date_string</span><span class="p">)</span>
<span class="k">if</span> <span class="n">message</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">message</span> <span class="o">=</span> <span class="s2">&quot;DMARC results for </span><span class="si">{0}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">date_string</span><span class="p">)</span>
<span class="n">zip_bytes</span> <span class="o">=</span> <span class="n">get_report_zip</span><span class="p">(</span><span class="n">results</span><span class="p">)</span>
<span class="n">attachments</span> <span class="o">=</span> <span class="p">[(</span><span class="n">filename</span><span class="p">,</span> <span class="n">zip_bytes</span><span class="p">)]</span>
<span class="k">return</span> <span class="n">subject</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">attachments</span>
<div class="viewcode-block" id="email_results">
<a class="viewcode-back" href="../api.html#parsedmarc.email_results">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">email_results</span><span class="p">(</span>
@@ -3002,22 +3054,14 @@
<span class="sd"> message (str): Override the default plain text body</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Emailing report&quot;</span><span class="p">)</span>
<span class="n">date_string</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&quot;%Y-%m-</span><span class="si">%d</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">attachment_filename</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">attachment_filename</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">&quot;.zip&quot;</span><span class="p">):</span>
<span class="n">attachment_filename</span> <span class="o">+=</span> <span class="s2">&quot;.zip&quot;</span>
<span class="n">filename</span> <span class="o">=</span> <span class="n">attachment_filename</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">filename</span> <span class="o">=</span> <span class="s2">&quot;DMARC-</span><span class="si">{0}</span><span class="s2">.zip&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">date_string</span><span class="p">)</span>
<span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">mail_to</span><span class="p">,</span> <span class="nb">list</span><span class="p">)</span>
<span class="k">if</span> <span class="n">subject</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">subject</span> <span class="o">=</span> <span class="s2">&quot;DMARC results for </span><span class="si">{0}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">date_string</span><span class="p">)</span>
<span class="k">if</span> <span class="n">message</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">message</span> <span class="o">=</span> <span class="s2">&quot;DMARC results for </span><span class="si">{0}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">date_string</span><span class="p">)</span>
<span class="n">zip_bytes</span> <span class="o">=</span> <span class="n">get_report_zip</span><span class="p">(</span><span class="n">results</span><span class="p">)</span>
<span class="n">attachments</span> <span class="o">=</span> <span class="p">[(</span><span class="n">filename</span><span class="p">,</span> <span class="n">zip_bytes</span><span class="p">)]</span>
<span class="n">subject</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">attachments</span> <span class="o">=</span> <span class="n">_build_report_email_content</span><span class="p">(</span>
<span class="n">results</span><span class="p">,</span>
<span class="n">subject</span><span class="o">=</span><span class="n">subject</span><span class="p">,</span>
<span class="n">attachment_filename</span><span class="o">=</span><span class="n">attachment_filename</span><span class="p">,</span>
<span class="n">message</span><span class="o">=</span><span class="n">message</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">send_email</span><span class="p">(</span>
<span class="n">host</span><span class="p">,</span>
@@ -3037,6 +3081,59 @@
<div class="viewcode-block" id="email_results_via_msgraph">
<a class="viewcode-back" href="../api.html#parsedmarc.email_results_via_msgraph">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">email_results_via_msgraph</span><span class="p">(</span>
<span class="n">results</span><span class="p">:</span> <span class="n">ParsingResults</span><span class="p">,</span>
<span class="n">connection</span><span class="p">:</span> <span class="n">MSGraphConnection</span><span class="p">,</span>
<span class="n">mail_to</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="p">,</span>
<span class="n">mail_cc</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">mail_bcc</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">subject</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">attachment_filename</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">message</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">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Emails parsing results as a zip file via an already-authenticated</span>
<span class="sd"> Microsoft Graph mailbox connection (``/users/{mailbox}/sendMail``),</span>
<span class="sd"> saving a copy to Sent Items.</span>
<span class="sd"> Args:</span>
<span class="sd"> results (dict): Parsing results</span>
<span class="sd"> connection (MSGraphConnection): An already-authenticated Microsoft</span>
<span class="sd"> Graph mailbox connection</span>
<span class="sd"> mail_to (list): A list of addresses to mail to</span>
<span class="sd"> mail_cc (list): A list of addresses to CC</span>
<span class="sd"> mail_bcc (list): A list addresses to BCC</span>
<span class="sd"> subject (str): Overrides the default message subject</span>
<span class="sd"> attachment_filename (str): Override the default attachment filename</span>
<span class="sd"> message (str): Override the default plain text body</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Emailing report via Microsoft Graph&quot;</span><span class="p">)</span>
<span class="n">subject</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">attachments</span> <span class="o">=</span> <span class="n">_build_report_email_content</span><span class="p">(</span>
<span class="n">results</span><span class="p">,</span>
<span class="n">subject</span><span class="o">=</span><span class="n">subject</span><span class="p">,</span>
<span class="n">attachment_filename</span><span class="o">=</span><span class="n">attachment_filename</span><span class="p">,</span>
<span class="n">message</span><span class="o">=</span><span class="n">message</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Graph derives the From header from the authenticated mailbox and</span>
<span class="c1"># ignores message_from; it&#39;s still passed for API parity with</span>
<span class="c1"># send_message()&#39;s signature.</span>
<span class="n">connection</span><span class="o">.</span><span class="n">send_message</span><span class="p">(</span>
<span class="n">message_from</span><span class="o">=</span><span class="n">connection</span><span class="o">.</span><span class="n">mailbox_name</span> <span class="ow">or</span> <span class="s2">&quot;&quot;</span><span class="p">,</span>
<span class="n">message_to</span><span class="o">=</span><span class="n">mail_to</span><span class="p">,</span>
<span class="n">message_cc</span><span class="o">=</span><span class="n">mail_cc</span><span class="p">,</span>
<span class="n">message_bcc</span><span class="o">=</span><span class="n">mail_bcc</span><span class="p">,</span>
<span class="n">subject</span><span class="o">=</span><span class="n">subject</span><span class="p">,</span>
<span class="n">attachments</span><span class="o">=</span><span class="n">attachments</span><span class="p">,</span>
<span class="n">plain_message</span><span class="o">=</span><span class="n">message</span><span class="p">,</span>
<span class="p">)</span></div>
<span class="c1"># Backward-compatible aliases</span>
<span class="n">parse_forensic_report</span> <span class="o">=</span> <span class="n">parse_failure_report</span>
<span class="n">parsed_forensic_reports_to_csv_rows</span> <span class="o">=</span> <span class="n">parsed_failure_reports_to_csv_rows</span>