{% extends "layout/base.html" %} {% block content %}

Parsers

Mail processing flow
  1. Retrieval
    Mail is retrieved from Microsoft Graph (manual or automatic import) and stored in the database as a MailMessage record including sender, subject, received time and message body (HTML and plain text).
  2. Preprocessing
    The message body is normalized (line endings, character set) so that the parsers can work with a consistent format.
  3. Parser selection
    All active parsers are evaluated in a fixed order. For each parser, match criteria like sender address, subject text and body snippets are checked.
  4. Parsing
    As soon as a parser matches, it extracts:
    • Backup software (for example: Veeam, NAKIVO, Panel3, Syncovery)
    • Backup type (for example: Backup Job, Backup Copy Job, Replication job for VMware)
    • Job name
    • Objects within the job (for example: VMs, servers, repositories) including their status and any error message
  5. Storage and linkage
    The parsed result is stored in the database:
    • Job – one record per backup job
    • JobRun – one record per run of a job
    • JobObject – one record per object inside a run
    The mail itself remains linked to the run via mail_message_id.
  6. Inbox and approval
    If a job for this mail has not been approved yet, the mail appears in the Inbox with the parsed result. After approval the run is shown on the Jobs and Daily Jobs pages.
Available parsers
{% if parsers %} {% for p in parsers %} {% endfor %} {% else %} {% endif %}
Name Backup software Backup type(s) Match criteria Order Enabled
{{ p.name }} {{ p.backup_software }} {% if p.backup_types %} {{ p.backup_types | join(", ") }} {% else %} - {% endif %} {% set parts = [] %} {% if p.match.from_contains %} {% set _ = parts.append("from contains '" ~ p.match.from_contains ~ "'") %} {% endif %} {% if p.match.subject_contains %} {% set _ = parts.append("subject contains '" ~ p.match.subject_contains ~ "'") %} {% endif %} {% if p.match.subject_regex %} {% set _ = parts.append("subject matches /" ~ p.match.subject_regex ~ "/") %} {% endif %} {% if parts %} {{ parts | join(", ") }} {% else %} - {% endif %} {{ p.order }} {% if p.enabled %} Enabled {% else %} Disabled {% endif %}
No parsers defined.
{% if parsers %} {% for p in parsers %}
{{ p.name }} – {{ p.backup_software }}{% if p.backup_types %} ({{ p.backup_types | join(", ") }}){% endif %}

{{ p.description }}

{% set ex_list = p.examples if p.examples is defined else ([p.example] if p.example is defined else []) %} {# Add supported Veeam backup-type examples that are configured/used in this installation. #} {% if p.backup_software == 'Veeam' %} {% set veeam_examples = [ { 'from_address': 'Veeam Backup & Replication ', 'subject': '[Success] Replication Job: VMware - DR Copy', 'body_snippet': 'Replication job "VMware - DR Copy" finished successfully\nObjects processed: 2\nVM01 - Success\nVM02 - Success', 'parsed_result': { 'backup_software': 'Veeam', 'backup_type': 'Replication Job', 'job_name': 'VMware - DR Copy', 'objects': [ {'name': 'VM01', 'status': 'success', 'error_message': ''}, {'name': 'VM02', 'status': 'success', 'error_message': ''} ] } }, { 'from_address': 'Veeam Agent ', 'subject': '[Warning] Agent Backup Job: LAPTOP-123', 'body_snippet': 'Agent backup job "LAPTOP-123" finished with warnings\n1 of 1 objects processed\nLAPTOP-123 - Warning', 'parsed_result': { 'backup_software': 'Veeam', 'backup_type': 'Agent Backup', 'job_name': 'LAPTOP-123', 'objects': [ {'name': 'LAPTOP-123', 'status': 'warning', 'error_message': 'Finished with warnings'} ] } }, { 'from_address': 'Veeam Backup for Microsoft 365 ', 'subject': '[Success] Microsoft 365 Backup Job: M365 Daily', 'body_snippet': 'Microsoft 365 backup job "M365 Daily" finished successfully\nObjects processed: 3\nExchange - Success\nSharePoint - Success\nOneDrive - Success', 'parsed_result': { 'backup_software': 'Veeam', 'backup_type': 'Microsoft 365 Backup', 'job_name': 'M365 Daily', 'objects': [ {'type': 'Exchange', 'name': 'Exchange', 'status': 'success', 'error_message': ''}, {'type': 'SharePoint', 'name': 'SharePoint', 'status': 'success', 'error_message': ''}, {'type': 'OneDrive', 'name': 'OneDrive', 'status': 'success', 'error_message': ''} ] } } , { 'from_address': 'Veeam Backup & Replication ', 'subject': '[Success] Scale-out Backup Repository: CEPH RBD', 'body_snippet': 'Scale-out Backup Repository: CEPH RBD Extents: - CEPH RBD1 - CEPH RBD2 Used Space: 107,6 TB Capacity: 200 TB (66% free)', 'parsed_result': { 'backup_software': 'Veeam', 'backup_type': 'Scale-out Backup Repository', 'job_name': 'CEPH RBD', 'overall_status': 'Success', 'objects': [ {'type': 'Extent', 'name': 'CEPH RBD1', 'status': 'Online', 'error_message': ''}, {'type': 'Extent', 'name': 'CEPH RBD2', 'status': 'Online', 'error_message': ''} ] } }, { 'from_address': 'Veeam Backup & Replication ', 'subject': '[Success] Health check (1 objects)', 'body_snippet': 'Health Check Summary\nSuccess: 1\nWarnings: 0\nErrors: 0\n\nObjects:\nHealthCheck Blygold DC01 - Success', 'parsed_result': { 'backup_software': 'Veeam', 'backup_type': 'Health Check', 'job_name': 'Health Check', 'overall_status': 'Success', 'objects': [ {'name': 'HealthCheck Blygold DC01', 'status': 'Success', 'error_message': ''} ] } } ] %} {% set ex_list = ex_list + veeam_examples %} {% endif %} {# Add Synology Active Backup examples. #} {% if p.backup_software == 'Synology' %} {% set synology_examples = [ { 'from_address': 'Synology Active Backup ', 'subject': 'NAS - Active Backup for Google Workspace - back-uptaak [Google D-Two] is gedeeltelijk voltooid', 'body_snippet': 'Back-up [Google D-Two] is voltooid, maar van sommige items kon geen back-up worden gemaakt.\n- Mijn schijf: succes: 0; waarschuwing: 11; fout: 0\n- Mail: succes: 0; waarschuwing: 11; fout: 0\nStarttijd: 2025-12-18 00:00:02\nEindtijd: 2025-12-18 00:01:38', 'parsed_result': { 'backup_software': 'Synology', 'backup_type': 'Active Backup', 'job_name': 'Google D-Two', 'overall_status': 'Warning', 'objects': [] } } , { 'from_address': 'SCHWARZNAS ', 'subject': 'Gegevensback-uptaak op SCHWARZNAS is mislukt', 'body_snippet': 'Gegevensback-uptaak op SCHWARZNAS is mislukt.\nTaaknaam: Data backup - NAS thuis\nGa naar Hyper Backup > Logboek voor meer informatie.', 'parsed_result': { 'backup_software': 'Synology', 'backup_type': 'Hyperbackup', 'job_name': 'Data backup - NAS thuis', 'overall_status': 'Failed', 'objects': [] } } , { 'from_address': 'DiskStation ', 'subject': '[Golfpark NAS] HiDrive cloud backup - NAS Backup - Strato HiDrive successful on DiskStation', 'body_snippet': 'Your backup task NAS Backup - Strato HiDrive is now complete.\n\nBackup Task: NAS Backup - Strato HiDrive\nBackup Destination: /users/.../DiskStation_1.hbk\nStart Time: Wed, Dec 17 2025 23:00:01\nDuration: 17 Minute 9 Second', 'parsed_result': { 'backup_software': 'Synology', 'backup_type': 'Strato HiDrive', 'job_name': 'NAS Backup - Strato HiDrive', 'overall_status': 'Success', 'objects': [] } }] %} {% set ex_list = ex_list + synology_examples %} {% endif %} {# Add NAKIVO VMware examples. #} {% if p.backup_software == 'NAKIVO' %} {% set nakivo_examples = [ { 'from_address': 'NAKIVO Backup & Replication ', 'subject': '"exchange01.kuiperbv.nl" job: Successful', 'body_snippet': 'Job Run Report\nBackup job for VMware\nexchange01.kuiperbv.nl\nSuccessful', 'parsed_result': { 'backup_software': 'NAKIVO', 'backup_type': 'Backup job for VMware', 'job_name': 'exchange01.kuiperbv.nl', 'overall_status': 'Success', 'objects': [ {'name': 'exchange01.kuiperbv.nl', 'status': 'success', 'error_message': ''} ] } } ] %} {% set ex_list = ex_list + nakivo_examples %} {% endif %} {% for ex in ex_list %}
Example {{ loop.index }}
From
{{ ex.from_address }}
Subject
{{ ex.subject }}
Body snippet
{{ ex.body_snippet }}
Parsed result
Backup software
{{ ex.parsed_result.backup_software }}
Backup type
{{ ex.parsed_result.backup_type }}
Job name
{{ ex.parsed_result.job_name }}
{% for obj in ex.parsed_result.objects %} {% set _s = (obj.status or "")|lower %} {% set _dot = '' %} {% if _s == 'success' %}{% set _dot = 'dot-success' %} {% elif _s == 'warning' %}{% set _dot = 'dot-warning' %} {% elif _s == 'error' %}{% set _dot = 'dot-failed' %} {% elif _s == 'failed' %}{% set _dot = 'dot-failed' %} {% elif _s == 'missed' %}{% set _dot = 'dot-missed' %} {% endif %} {% endfor %}
Type Object Status Error message
{{ obj.type or '' }} {{ obj.name }}{% if _dot %}{% endif %}{{ obj.status }} {{ obj.error_message }}
{% if not loop.last %}
{% endif %} {% endfor %}
{% endfor %} {% endif %} {% endblock %}