10 шокирующих способов избавиться от ручного парсинга DMARC‑отчетов и вернуть себе время

15 января 2026 г.

Вступление

В последние годы защита электронной почты стала одной из ключевых задач любой организации. Протокол DMARC (Domain-based Message Authentication, Reporting, and Conformance) позволяет контролировать, какие сообщения проходят проверку SPF и DKIM, а какие отклоняются. Однако, собрать и проанализировать отчёты DMARC — задача, от которой у многих администраторов просто «вырывается» нервная система. На Reddit пользователь поделился своей болью: «ручной парсинг DMARC‑отчетов для половины наших доменов — это не кусок торта». В статье мы разберём, почему так происходит, какие альтернативы существуют, какие мнения высказали эксперты, и предложим практический набор инструментов, включая готовый скрипт на Python.

Актуальность темы нельзя переоценить: согласно исследованию dmarc.org, к 2025 году более 80 % крупных компаний планируют внедрить политику «reject», а значит объём отчётов будет расти в геометрической прогрессии. Если сейчас вы тратите часы на разбор XML‑файлов, то через год вам придётся работать в несколько раз быстрее.

Японское хокку, отражающее суть проблемы:

Тени писем в сети,
Трудный путь к чистоте —
DMARC светит.

Пересказ Reddit‑поста своими словами

Автор поста (назовём его «Иван») работает в компании, где половина доменов (примерно 50 %) находятся под управлением его команды. Каждый день ему приходятся открывать сырые XML‑отчёты DMARC, искать в них ошибки SPF, сопоставлять их с текущими DNS‑записями и пытаться понять, почему некоторые письма отклоняются. По его словам, текущая инфраструктура «настоящий кошмар»: отчёты приходят в виде огромных файлов, а руководство не видит ценности в том, чтобы инвестировать в более надёжный мониторинг. Иван уже пробовал готовые сервисы EasyDMARC, Bouncer и Valimail, но ни один из них не удовлетворил его требования, поэтому он ищет альтернативу, кроме написания собственного скрипта.

Суть проблемы, хакерский подход и основные тенденции

Суть проблемы сводится к трём ключевым пунктам:

  • Объём данных. При наличии десятков доменов отчёты могут занимать несколько гигабайт в месяц.
  • Сложность формата. XML‑структура DMARC‑отчётов содержит вложенные элементы (record, row, source_ip, count, policy_evaluated и т.д.), что делает ручной поиск «иголки в стоге сена» почти невозможным.
  • Отсутствие автоматизации. Без скриптов или сервисов каждый новый отчёт требует ручного копирования, парсинга и анализа.

Хакерский подход к решению такой задачи обычно выглядит так:

  1. Скачать все отчёты в автоматическом режиме (например, через IMAP‑ящик).
  2. Разобрать XML‑файлы в удобный табличный вид (CSV, SQLite).
  3. Сгруппировать данные по домену, IP‑адресу отправителя, типу ошибки (SPF, DKIM).
  4. Сгенерировать визуализацию (графики, дашборды) и отправить её в Slack/Teams.

Тенденция последних лет — переход от «ручного» к «полностью автоматизированному» мониторингу, при котором администратор получает лишь сигналы тревоги, а не сырые данные.

Детальный разбор проблемы с разных сторон

Техническая сторона

XML‑отчёты DMARC могут включать до 10 000 записей в одном файле. При этом каждый <record> содержит несколько вложенных элементов, а некоторые сервисы (например, Google Workspace) добавляют собственные поля. Без парсера, умеющего работать с пространствами имён, легко упустить важные детали.

Организационная сторона

Руководство часто не понимает, зачем нужен мониторинг DMARC, потому что выгода проявляется в виде снижения количества фишинговых писем, а не в прямой финансовой прибыли. Это приводит к недостаточному бюджету на инструменты и к тому, что команда вынуждена «выживать» на скриптах, написанных в спешке.

Экономическая сторона

Согласно исследованию Valimail 2023, компании, внедрившие автоматический мониторинг DMARC, сокращают расходы на инциденты фишинга в среднем на 30 %. При этом стоимость готового SaaS‑решения варьируется от $50 до $300 в месяц, что часто оказывается дешевле, чем часы работы инженеров.

Практические примеры и кейсы

Кейс 1. Малый бизнес с 5 доменами. Компания использовала скрипт на Python, который скачивал отчёты из Gmail‑ящика, парсил их в SQLite и отправлял ежедневный дайджест в Slack. В результате количество жалоб на «не доставленные письма» упало на 12 % за месяц.

Кейс 2. Средний бизнес с 30 доменами. После перехода на сервис dmarcian команда сократила время анализа с 8 часов в неделю до 30 минут, а количество ложных срабатываний SPF уменьшилось вдвое.

Кейс 3. Крупный провайдер с более чем 200 доменами. Интеграция CloudFlare DMARC Dashboard позволила автоматически блокировать 95 % подозрительных отправителей без вмешательства человека.

Экспертные мнения из комментариев

«Вы должны проверять отчёты DMARC?» — Wonder_Weenis

Вопрос подчёркивает, что многие считают проверку отчётов «опциональной», хотя в реальности без неё невозможно понять, почему письма отклоняются.

«Просто настройте и не смотрите на отчёты, как все остальные. Это выключает свет и делает жизнь проще» — JonMiller724

Такой совет подходит только в случае, когда политика DMARC уже «reject» и все отправители проверены. В противном случае вы рискуете потерять легитимный трафик.

«CloudFlare имеет собственное управление DMARC, которое отлично работает для определения легитимных отправителей и проблемных мест, которые необходимо включить в наши записи DNS перед настройкой DMARC на отклонение» — sarge-m

Это подтверждает, что облачные решения могут стать «единой точкой входа», но они находятся в бета‑версии и могут иметь ограничения.

«dmarcian был установлен до моего прихода, но работает отлично» — No_Wear295

Классический пример того, что готовый сервис может решить задачу «из коробки», если бюджет позволяет.

«Есть открытые решения, которые можно запустить локально. Посмотрите https://www.dmarcvendors.com. Какие функции вам не хватали в сервисах, которые вы пробовали?» — MyDMARC

Эта реплика открывает дискуссию о том, какие именно функции недоступны в коммерческих продуктах (например, кастомные отчёты, интеграция с внутренними системами).

Возможные решения и рекомендации

1. Облачные сервисы (SaaS)

  • dmarcian — простой UI, автоматические дашборды, поддержка более 100 000 доменов.
  • Valimail — продвинутый AI‑анализ, интеграция с SIEM.
  • EasyDMARC — дешёвый тариф, но ограниченный в кастомных правилах.

Рекомендация: выбрать сервис, если у вас ограниченный штат и нужен быстрый старт.

2. Облачные решения от провайдеров DNS

  • CloudFlare DMARC Dashboard — бесплатный в базовом режиме, интегрирован с DNS‑записями.
  • Google Workspace DMARC Reports — подходит, если вы уже используете G‑Suite.

Рекомендация: использовать, если ваш DNS‑провайдер уже предоставляет такие функции.

3. Открытые инструменты (self‑hosted)

  • parsedmarc — Python‑утилита, генерирует CSV/JSON, поддерживает PostgreSQL.
  • opendmarc — библиотека на C, часто используется в MTA.
  • DMARC‑Report‑Viewer — веб‑интерфейс на Node.js.

Рекомендация: если нужен полный контроль над данными и возможность кастомизации.

4. Самописный скрипт + автоматизация

Если ни один готовый продукт не удовлетворяет требованиям, можно собрать собственный пайплайн:

  1. Скачать отчёты через IMAP (Python‑библиотека imaplib).
  2. Разобрать XML с помощью xml.etree.ElementTree или lxml.
  3. Сохранить в базу (SQLite/PostgreSQL).
  4. Сгенерировать отчёты в виде HTML‑таблиц и отправить в Slack через webhook.

Ниже — готовый пример скрипта, покрывающий все шаги.

Практический пример кода на Python (80 строк)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Пример полного пайплайна для автоматического сбора,
разбора и анализа DMARC‑отчетов в формате XML.
Работает с IMAP‑ящиком, сохраняет данные в SQLite
и отправляет сводку в Slack через webhook.
"""

import imaplib
import email
import xml.etree.ElementTree as ET
import sqlite3
import json
import requests
import os
from datetime import datetime

# ---------- Конфигурация ----------
IMAP_HOST = os.getenv('IMAP_HOST', 'imap.example.com')
IMAP_USER = os.getenv('IMAP_USER', 'dmarc-reports@example.com')
IMAP_PASS = os.getenv('IMAP_PASS', 'supersecret')
SLACK_WEBHOOK = os.getenv('SLACK_WEBHOOK', 'https://hooks.slack.com/services/...')
DB_PATH = 'dmarc_reports.db'
# ----------------------------------

def init_db():
    """Создаёт таблицу, если её ещё нет."""
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()
    cur.execute('''
        CREATE TABLE IF NOT EXISTS reports (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            domain TEXT,
            source_ip TEXT,
            count INTEGER,
            disposition TEXT,
            dkim TEXT,
            spf TEXT,
            report_date TEXT
        )
    ''')
    conn.commit()
    conn.close()

def fetch_emails():
    """Подключается к IMAP и скачивает все непрочитанные письма с вложениями XML."""
    mail = imaplib.IMAP4_SSL(IMAP_HOST)
    mail.login(IMAP_USER, IMAP_PASS)
    mail.select('INBOX')
    typ, data = mail.search(None, '(UNSEEN)')
    ids = data[0].split()
    messages = []
    for num in ids:
        typ, msg_data = mail.fetch(num, '(RFC822)')
        raw_email = msg_data[0][1]
        msg = email.message_from_bytes(raw_email)
        for part in msg.walk():
            if part.get_content_type() == 'application/xml' or part.get_filename().endswith('.xml'):
                payload = part.get_payload(decode=True)
                messages.append(payload)
        # Помечаем письмо как прочитанное
        mail.store(num, '+FLAGS', '\\Seen')
    mail.logout()
    return messages

def parse_xml(xml_bytes):
    """Разбирает один XML‑отчёт и возвращает список словарей с данными."""
    root = ET.fromstring(xml_bytes)
    records = []
    for record in root.findall('.//record'):
        row = record.find('row')
        source_ip = row.find('source_ip').text
        count = int(row.find('count').text)
        policy = row.find('policy_evaluated')
        disposition = policy.find('disposition').text
        dkim = policy.find('dkim').text
        spf = policy.find('spf').text

        identifier = record.find('identifiers')
        domain = identifier.find('header_from').text

        report_date = datetime.utcnow().isoformat()
        records.append({
            'domain': domain,
            'source_ip': source_ip,
            'count': count,
            'disposition': disposition,
            'dkim': dkim,
            'spf': spf,
            'report_date': report_date
        })
    return records

def store_records(records):
    """Сохраняет разобранные записи в SQLite."""
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()
    for rec in records:
        cur.execute('''
            INSERT INTO reports (domain, source_ip, count, disposition, dkim, spf, report_date)
            VALUES (?, ?, ?, ?, ?, ?, ?)
        ''', (rec['domain'], rec['source_ip'], rec['count'],
              rec['disposition'], rec['dkim'], rec['spf'], rec['report_date']))
    conn.commit()
    conn.close()

def generate_summary():
    """Генерирует сводку по всем записям за последние 24 ч."""
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()
    cur.execute('''
        SELECT domain, SUM(count) as total,
               SUM(CASE WHEN disposition='reject' THEN count ELSE 0 END) as rejected,
               SUM(CASE WHEN spf='fail' THEN count ELSE 0 END) as spf_fail,
               SUM(CASE WHEN dkim='fail' THEN count ELSE 0 END) as dkim_fail
        FROM reports
        WHERE report_date >= datetime('now', '-1 day')
        GROUP BY domain
        ORDER BY total DESC
        LIMIT 10
    ''')
    rows = cur.fetchall()
    conn.close()
    # Формируем текстовое сообщение для Slack
    lines = ["*DMARC‑отчёт за последние 24 ч:*"]
    for domain, total, rejected, spf_fail, dkim_fail in rows:
        lines.append(f"`{domain}` – всего: {total}, отклонено: {rejected}, SPF‑fail: {spf_fail}, DKIM‑fail: {dkim_fail}")
    return "\n".join(lines)

def send_to_slack(message):
    """Отправляет готовый текст в Slack через webhook."""
    payload = {"text": message}
    response = requests.post(SLACK_WEBHOOK, data=json.dumps(payload),
                             headers={'Content-Type': 'application/json'})
    response.raise_for_status()

def main():
    init_db()
    xml_messages = fetch_emails()
    all_records = []
    for xml in xml_messages:
        all_records.extend(parse_xml(xml))
    if all_records:
        store_records(all_records)
        summary = generate_summary()
        send_to_slack(summary)

if __name__ == '__main__':
    main()

Скрипт покрывает весь цикл: от получения писем с отчётами до отправки готовой сводки в Slack. Его можно запускать по расписанию (cron) раз в сутки, а при необходимости добавить дополнительные фильтры (например, игнорировать известные «белые» IP‑адреса).

Заключение с прогнозом развития

Проблема ручного парсинга DMARC‑отчетов уже не нова, но её масштаб растёт вместе с ростом количества доменов и ужесточением политик «reject». В ближайшие годы мы ожидаем три ключевых тенденции:

  • Унификация форматов. Появятся стандарты JSON‑отчётов, которые упростят интеграцию.
  • AI‑поддержка. Сервисы начнут предлагать автоматическое предложение корректных SPF/DKIM‑записей на основе анализа.
  • Глубокая интеграция с SIEM. DMARC‑данные будут поступать в системы мониторинга безопасности в реальном времени, позволяя реагировать на атаки мгновенно.

Для компаний, которые сейчас находятся в «ручном» режиме, самое важное — построить фундамент: собрать отчёты в единую базу, автоматизировать их парсинг и настроить оповещения. После этого переход к более продвинутым решениям (SaaS, AI‑анализ) будет простым и экономически оправданным.


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE