{"id":21685,"library":"parsedmarc","title":"parsedmarc","description":"A Python package and CLI for parsing aggregate and forensic DMARC reports. Current version 9.10.3, requires Python >=3.10. Released regularly with new features and bug fixes.","status":"active","version":"9.10.3","language":"python","source_language":"en","source_url":"https://github.com/domainaware/parsedmarc","tags":["dmarc","email-security","dns","dmarcian","parsing","cli"],"install":[{"cmd":"pip install parsedmarc","lang":"bash","label":"Install from PyPI"},{"cmd":"pip install parsedmarc[elasticsearch,geoip2]","lang":"bash","label":"Install with Elasticsearch and GeoIP support"}],"dependencies":[{"reason":"Optional dependency for Elasticsearch output","package":"elasticsearch","optional":true},{"reason":"Optional dependency for GeoIP lookups","package":"geoip2","optional":true},{"reason":"Optional dependency for Kafka output","package":"kafka-python","optional":true},{"reason":"Optional dependency for SPF checks","package":"pyspf","optional":true},{"reason":"Optional dependency for Threat Grid integration","package":"pythreatgrid2","optional":true}],"imports":[{"note":"Common mistake: using module-level import instead of submodule","wrong":"import parsedmarc; parsedmarc.parse_aggregate_report_xml","symbol":"parse_aggregate_report_xml","correct":"from parsedmarc import parse_aggregate_report_xml"},{"note":"Direct function access without import works but less explicit","wrong":"parsedmarc.parse_forensic_report_xml","symbol":"parse_forensic_report_xml","correct":"from parsedmarc import parse_forensic_report_xml"},{"note":"This class is available in newer versions (8.x+). Older versions used a different internal structure.","symbol":"ParsedReport","correct":"from parsedmarc import ParsedReport"}],"quickstart":{"code":"import os\nfrom parsedmarc import parse_aggregate_report_xml\n\n# Example: parse an aggregate DMARC report from a file\nwith open('aggregate_report.xml', 'r') as f:\n    xml_data = f.read()\n\nparsed = parse_aggregate_report_xml(xml_data)\nprint(parsed)\n\n# If using IMAP, ensure credentials are set (optional)\nos.environ.get('IMAP_HOST', 'imap.example.com')","lang":"python","description":"Minimal example to parse an aggregate DMARC XML report."},"warnings":[{"fix":"Access attributes via the ParsedReport object (e.g., report.policy_published) instead of dict keys.","message":"In version 8.0.0, the output format from parsedmarc changed from a list of dictionaries to a list of ParsedReport objects. Code relying on dictionary keys will break.","severity":"breaking","affected_versions":">=8.0.0"},{"fix":"Use Python >=3.10. Update environment or use older parsedmarc version (<=8.x).","message":"Support for Python 3.6 was dropped in version 7.0.0; Python 3.9 dropped in 9.0.0; Python 3.10 is required starting 9.0.0.","severity":"breaking","affected_versions":"9.0.0+"},{"fix":"Use the command-line option '--es-create-index' or set the environment variable PARSEDMARC_ES_CREATE_INDEX=true.","message":"When using parsedmarc with Elasticsearch, the index mapping must be created manually or via the CLI '--es-index' flag. If not created, parsedmarc will not write to Elasticsearch and may fail silently.","severity":"gotcha","affected_versions":"all"},{"fix":"Set the environment variable PARSEDMARC_GEOIP_DB_PATH to the path of the MMDB file, or place the file in the default location.","message":"GeoIP lookups require the GeoIP2 database file (GeoLite2-City.mmdb). If not present and geoip2 is installed, parsing will fail with FileNotFoundError.","severity":"gotcha","affected_versions":"all"},{"fix":"Use parse_report() instead. It accepts the same arguments.","message":"The function parse_report_email() is deprecated in favor of parse_report() since version 7.0.0.","severity":"deprecated","affected_versions":"7.0.0+"}],"env_vars":null,"last_verified":"2026-04-27T00:00:00.000Z","next_check":"2026-07-26T00:00:00.000Z","problems":[{"fix":"Ensure the input to parse_* functions is a string (not bytes). Use .decode() if reading from binary mode.","cause":"Python 3 compatibility: bytes.decode() used, but string passed.","error":"AttributeError: 'str' object has no attribute 'decode'"},{"fix":"Upgrade pip and reinstall: pip install --upgrade parsedmarc","cause":"Missing resource package in installation; usually happens with older pip or incomplete install.","error":"ModuleNotFoundError: No module named 'parsedmarc.resources'"},{"fix":"Uninstall and reinstall: pip uninstall parsedmarc -y; pip install parsedmarc","cause":"Internal resource reading error due to broken package, often after upgrading from very old version.","error":"KeyError: 'email' in parsedmarc.resources.files"},{"fix":"Use parsedmarc.__version__ (string) and parse with packaging.version.parse for comparisons.","cause":"Comparing version strings incorrectly; custom code sometimes passes wrong types.","error":"TypeError: '>' not supported between instances of 'str' and 'int'"}],"ecosystem":"pypi","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null}