[GH-ISSUE #3846] DMARC: import_aggregated_report crashes when auth_results domain is missing (NotNullViolation on dmarc_result.domain) #1924

Open
opened 2026-02-27 11:19:55 +03:00 by kerem · 2 comments
Owner

Originally created by @jg-shinji-ueda on GitHub (Dec 25, 2025).
Original GitHub issue: https://github.com/modoboa/modoboa/issues/3846

Originally assigned to: @tonioo on GitHub.

Impacted versions

  • OS Type: Ubuntu
  • OS Version: 24.04
  • Database Type: PostgreSQL
  • Database version: 16.11
  • Modoboa: 2.6.5
  • installer used: Yes
  • Webserver: Nginx

Additional:

  • Python: 3.12.3
  • DMARC importer path: site-packages/modoboa/dmarc/lib.py

Steps to reproduce

  1. Receive a DMARC aggregate report where an auth_results entry has a missing or empty domain value, e.g. <auth_results><dkim><domain/></dkim>...</auth_results> (domain text becomes None).
  2. Import it using the management command (pipe mode):
   /path/to/python /path/to/manage.py import_aggregated_report --pipe < report.eml

Current behavior

The import crashes with a PostgreSQL NOT NULL constraint violation:

psycopg.errors.NotNullViolation: null value in column "domain" of relation "dmarc_result" violates not-null constraint
DETAIL:  Failing row contains (..., dkim, null, fail, ...)

Because the importer is commonly executed via Postfix pipe delivery, the crash can cause DMARC report emails to bounce and ingestion to stop.

Expected behavior

The importer should not crash when the <auth_results><dkim|spf><domain> value is missing/empty. It should safely handle this case, for example by:

  • storing an empty string, or
  • falling back to a reasonable value such as identifiers/header_from (or the already-resolved local record.header_from.name), and continuing the import.

Video/Screenshot link (optional)

N/A


Notes / suspected root cause

In modoboa/dmarc/lib.py, the importer currently does:

domain = rnode.find("domain").text

If the <domain> element is present but empty (<domain/>) or missing, .text can be None, leading to a NULL insert into dmarc_result.domain (NOT NULL), and the import aborts.

Proposed fix (minimal)

Use findtext() and a fallback to avoid inserting NULL:

diff --git a/modoboa/dmarc/lib.py b/modoboa/dmarc/lib.py
@@ -81,11 +81,16 @@
       for rtype in ["spf", "dkim"]:
           rnode = auth_results.find(rtype)
           if not rnode:
               continue
+          domain = (rnode.findtext("domain") or "").strip()
+          if not domain:
+              domain = record.header_from.name
+          result = (rnode.findtext("result") or "").strip()
           models.Result.objects.create(
               record=record,
               type=rtype,
-              domain=rnode.find("domain").text,
-              result=rnode.find("result").text,
+              domain=domain,
+              result=result,
           )

I can provide a sanitized minimal XML/EML snippet to reproduce if needed (with domains/IPs removed).

Originally created by @jg-shinji-ueda on GitHub (Dec 25, 2025). Original GitHub issue: https://github.com/modoboa/modoboa/issues/3846 Originally assigned to: @tonioo on GitHub. # Impacted versions * OS Type: Ubuntu * OS Version: 24.04 * Database Type: PostgreSQL * Database version: 16.11 * Modoboa: 2.6.5 * installer used: Yes * Webserver: Nginx Additional: * Python: 3.12.3 * DMARC importer path: `site-packages/modoboa/dmarc/lib.py` # Steps to reproduce 1. Receive a DMARC aggregate report where an auth_results entry has a missing or empty domain value, e.g. `<auth_results><dkim><domain/></dkim>...</auth_results>` (domain text becomes `None`). 2. Import it using the management command (pipe mode): ```bash /path/to/python /path/to/manage.py import_aggregated_report --pipe < report.eml ```` # Current behavior The import crashes with a PostgreSQL NOT NULL constraint violation: ``` psycopg.errors.NotNullViolation: null value in column "domain" of relation "dmarc_result" violates not-null constraint DETAIL: Failing row contains (..., dkim, null, fail, ...) ``` Because the importer is commonly executed via Postfix pipe delivery, the crash can cause DMARC report emails to bounce and ingestion to stop. # Expected behavior The importer should not crash when the `<auth_results><dkim|spf><domain>` value is missing/empty. It should safely handle this case, for example by: * storing an empty string, or * falling back to a reasonable value such as `identifiers/header_from` (or the already-resolved local `record.header_from.name`), and continuing the import. # Video/Screenshot link (optional) N/A --- ## Notes / suspected root cause In `modoboa/dmarc/lib.py`, the importer currently does: ```python domain = rnode.find("domain").text ``` If the `<domain>` element is present but empty (`<domain/>`) or missing, `.text` can be `None`, leading to a NULL insert into `dmarc_result.domain` (NOT NULL), and the import aborts. ## Proposed fix (minimal) Use `findtext()` and a fallback to avoid inserting NULL: ```diff diff --git a/modoboa/dmarc/lib.py b/modoboa/dmarc/lib.py @@ -81,11 +81,16 @@ for rtype in ["spf", "dkim"]: rnode = auth_results.find(rtype) if not rnode: continue + domain = (rnode.findtext("domain") or "").strip() + if not domain: + domain = record.header_from.name + result = (rnode.findtext("result") or "").strip() models.Result.objects.create( record=record, type=rtype, - domain=rnode.find("domain").text, - result=rnode.find("result").text, + domain=domain, + result=result, ) ``` I can provide a sanitized minimal XML/EML snippet to reproduce if needed (with domains/IPs removed). ````
Author
Owner

@tonioo commented on GitHub (Jan 6, 2026):

@jg-shinji-ueda Can you please provide a snippet?

<!-- gh-comment-id:3713632010 --> @tonioo commented on GitHub (Jan 6, 2026): @jg-shinji-ueda Can you please provide a snippet?
Author
Owner

@jg-shinji-ueda commented on GitHub (Feb 17, 2026):

@tonioo

https://github.com/modoboa/modoboa/issues/3846#issuecomment-3713632010

Sorry for late reply, and thank you for implements and fix. 😄

<!-- gh-comment-id:3911323858 --> @jg-shinji-ueda commented on GitHub (Feb 17, 2026): @tonioo https://github.com/modoboa/modoboa/issues/3846#issuecomment-3713632010 Sorry for late reply, and thank you for implements and fix. 😄
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/modoboa-modoboa#1924
No description provided.