AutomationFlowsEmail & Gmail › Parse Dmarc Reports, Save Them in Database and Notify on Dkim or Spf Error

Parse Dmarc Reports, Save Them in Database and Notify on Dkim or Spf Error

ByŁukasz @lukaszpp on n8n.io

If you are a postmaster or you manage email server, you can set up DKIM and SPF records to ensure that spoofing your email address is hard. On your domain you can also set up DMARC record to receive XML reports from email providers (rua tag). Those reports contain data if email…

Manual trigger★★★★☆ complexity20 nodesEmail Read ImapMySQLCompressionXMLSlackEmail Send
Email & Gmail Trigger: Manual Nodes: 20 Complexity: ★★★★☆ Added:
Parse Dmarc Reports, Save Them in Database and Notify on Dkim or Spf Error — n8n workflow card showing Email Read Imap, MySQL, Compression integration

This workflow corresponds to n8n.io template #2369 — we link there as the canonical source.

This workflow follows the Emailreadimap → Emailsend recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "ATxZ5QYhdJq9mZDO",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Parse DMARC reports",
  "tags": [
    {
      "id": "w055QEEFrp6ZYNCr",
      "name": "DevOps",
      "createdAt": "2023-12-19T18:45:02.513Z",
      "updatedAt": "2023-12-19T18:45:02.513Z"
    }
  ],
  "nodes": [
    {
      "id": "ce9ce59c-3cf6-45db-97fc-825cb8516da8",
      "name": "Email Trigger (IMAP)",
      "type": "n8n-nodes-base.emailReadImap",
      "position": [
        580,
        300
      ],
      "parameters": {
        "options": {},
        "downloadAttachments": true
      },
      "credentials": {
        "imap": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "903f949d-ab1e-48ec-a903-a1ebde4cfbe9",
      "name": "End date format",
      "type": "n8n-nodes-base.dateTime",
      "position": [
        800,
        880
      ],
      "parameters": {
        "date": "={{ $json.date_range_end.toDateTime('s') }}",
        "format": "custom",
        "options": {
          "includeInputFields": true
        },
        "operation": "formatDate",
        "customFormat": "yyyy-MM-dd hh:mm:ss",
        "outputFieldName": "=date_range_end"
      },
      "typeVersion": 2
    },
    {
      "id": "3303e551-8557-4220-ab24-48fcb0859a26",
      "name": "If multiple records to parse",
      "type": "n8n-nodes-base.if",
      "position": [
        560,
        620
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "b809e758-c3d2-4cbf-bab8-54d278a435dd",
              "operator": {
                "type": "object",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.feedback.record[0] }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "513864bc-c124-452d-8be3-44feb73454ed",
      "name": "Map fields for DB input and parse",
      "type": "n8n-nodes-base.set",
      "position": [
        1200,
        660
      ],
      "parameters": {
        "options": {
          "ignoreConversionErrors": true
        },
        "assignments": {
          "assignments": [
            {
              "id": "621508ee-fbea-4233-aaf3-96b573a60bd5",
              "name": "full_data",
              "type": "object",
              "value": "={{ $json.feedback }}"
            },
            {
              "id": "d605e93a-0e0a-4584-aa1e-e38b49f264e7",
              "name": "org_name",
              "type": "string",
              "value": "={{ $json.feedback.report_metadata.org_name }}"
            },
            {
              "id": "604a5573-67db-4bb6-80d8-4421dce2406b",
              "name": "date_range_begin",
              "type": "string",
              "value": "={{ $json.feedback.report_metadata.date_range.begin }}"
            },
            {
              "id": "b9d7244f-9d58-43fc-a477-f0750c31e5e2",
              "name": "date_range_end",
              "type": "string",
              "value": "={{ $json.feedback.report_metadata.date_range.end }}"
            },
            {
              "id": "3570869a-9dc9-4b20-b48c-5f382825d021",
              "name": "domain",
              "type": "string",
              "value": "={{ $json.feedback.policy_published.domain }}"
            },
            {
              "id": "979e4eb4-6e39-4a3c-8f0a-21ecf8086a3c",
              "name": "policy_published",
              "type": "object",
              "value": "={{ $json.feedback.policy_published }}"
            },
            {
              "id": "91cdfa19-49c6-4e5d-a423-d76bbb61eddc",
              "name": "source_ip",
              "type": "string",
              "value": "={{ $json['fbr'].row.source_ip }}"
            },
            {
              "id": "2434b04e-3c5e-4e61-8be9-1f9c1ec2a6ce",
              "name": "mail_count",
              "type": "string",
              "value": "={{ $json['fbr'].row.count }}"
            },
            {
              "id": "09b73b84-0f6a-443b-8da0-c7ad9742a9c1",
              "name": "evaluated_disposition",
              "type": "string",
              "value": "={{ $json['fbr'].row.policy_evaluated.disposition }}"
            },
            {
              "id": "6c8e81ab-abc6-497c-8919-6b2e8008a1e8",
              "name": "evaluated_dkim",
              "type": "string",
              "value": "={{ $json['fbr'].row.policy_evaluated.dkim }}"
            },
            {
              "id": "fa8ca9d6-5e1b-402c-9afc-e6bf42e2c6ad",
              "name": "evaluated_spf",
              "type": "string",
              "value": "={{ $json['fbr'].row.policy_evaluated.spf }}"
            },
            {
              "id": "42f269c3-978a-45f6-bfe5-1fa1536500fb",
              "name": "identifiers",
              "type": "object",
              "value": "={{ $json['fbr'].identifiers }}"
            },
            {
              "id": "3375dc26-a739-4bf9-8a46-2f6739337921",
              "name": "auth_results",
              "type": "object",
              "value": "={{ $json['fbr'].auth_results }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "00cca3ae-1f0a-4ea9-8fb7-ac52d35c261b",
      "name": "Begin format date",
      "type": "n8n-nodes-base.dateTime",
      "position": [
        560,
        880
      ],
      "parameters": {
        "date": "={{ $json.date_range_begin.toDateTime('s') }}",
        "format": "custom",
        "options": {
          "includeInputFields": true
        },
        "operation": "formatDate",
        "customFormat": "yyyy-MM-dd hh:mm:ss",
        "outputFieldName": "=date_range_begin"
      },
      "typeVersion": 2
    },
    {
      "id": "18c2305a-db44-4e4d-97b9-1f04018085b0",
      "name": "Input into database",
      "type": "n8n-nodes-base.mySql",
      "position": [
        620,
        1100
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "dmarc",
          "cachedResultName": "dmarc"
        },
        "options": {
          "detailedOutput": true
        },
        "dataMode": "defineBelow",
        "valuesToSend": {
          "values": [
            {
              "value": "={{ $json.full_data.toJsonString() }}",
              "column": "full_data"
            },
            {
              "value": "={{ $json.org_name }}",
              "column": "org_name"
            },
            {
              "value": "={{ $json.date_range_begin }}",
              "column": "date_range_begin"
            },
            {
              "value": "={{ $json.date_range_end }}",
              "column": "date_range_end"
            },
            {
              "value": "={{ $json.domain }}",
              "column": "domain"
            },
            {
              "value": "={{ $json.policy_published.toJsonString() }}",
              "column": "policy_published"
            },
            {
              "value": "={{ $json.source_ip }}",
              "column": "source_ip"
            },
            {
              "value": "={{ $json.mail_count }}",
              "column": "mail_count"
            },
            {
              "value": "={{ $json.evaluated_disposition }}",
              "column": "evaluated_disposition"
            },
            {
              "value": "={{ $json.evaluated_dkim }}",
              "column": "evaluated_dkim"
            },
            {
              "value": "={{ $json.evaluated_spf }}",
              "column": "evaluated_spf"
            },
            {
              "value": "={{ $json.identifiers == null ? null : $json.identifiers.toJsonString() }}",
              "column": "identifiers"
            },
            {
              "value": "={{ $json.auth_results == null ? null : $json.auth_results.toJsonString() }}",
              "column": "auth_results"
            }
          ]
        }
      },
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.4
    },
    {
      "id": "c65c4cfb-3912-4b45-a5e0-3ab787e018c8",
      "name": "If issue with DKIM or SPF",
      "type": "n8n-nodes-base.if",
      "position": [
        580,
        1260
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "818b461b-4bdc-4842-9f89-d1d8966b8c0a",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.evaluated_dkim }}",
              "rightValue": "pass"
            },
            {
              "id": "4322cb26-5ff1-4278-94ae-7ff278c61c6c",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.evaluated_spf }}",
              "rightValue": "pass"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "5d17bf15-ecef-40e8-acc4-6af5ad1c712d",
      "name": "Rename Keys",
      "type": "n8n-nodes-base.renameKeys",
      "position": [
        1000,
        500
      ],
      "parameters": {
        "keys": {
          "key": [
            {
              "newKey": "fbr",
              "currentKey": "feedback.record"
            }
          ]
        },
        "additionalOptions": {}
      },
      "typeVersion": 1
    },
    {
      "id": "0e2b8c73-0f53-46f9-9692-cbe87c97862d",
      "name": "Rename column for consistency",
      "type": "n8n-nodes-base.set",
      "position": [
        800,
        660
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "f563d673-bc82-4863-b132-d431ebe8f651",
              "name": "fbr",
              "type": "object",
              "value": "={{ $json.feedback.record }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "5796c124-645d-460e-88df-0a909a33b6b1",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        100,
        300
      ],
      "parameters": {
        "width": 394.2691415313225,
        "height": 304.36194895591655,
        "content": "## How it works\n- monitor postmaster email for DKIM reprots\n- unpack report and parse XML\n- map and format fields for DB input\n\t- input into database\n\t- send notification on DKIM or SPF failure\n\n## Remember to set up\n- email input mailbox\n- notification channels"
      },
      "typeVersion": 1
    },
    {
      "id": "1457272e-630e-44ee-bb18-ac650d192cbf",
      "name": "Unzip File",
      "type": "n8n-nodes-base.compression",
      "position": [
        800,
        300
      ],
      "parameters": {
        "binaryPropertyName": "attachment_0"
      },
      "typeVersion": 1.1
    },
    {
      "id": "89ade90c-c7e3-4c6f-89cf-0e7ce1e55333",
      "name": "Extract XML data",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        1020,
        300
      ],
      "parameters": {
        "options": {},
        "operation": "xml",
        "binaryPropertyName": "file_0"
      },
      "typeVersion": 1
    },
    {
      "id": "8fd70f3c-53d5-4d99-ad2c-d526089fe0f5",
      "name": "Parse XML data to JSON",
      "type": "n8n-nodes-base.xml",
      "position": [
        1220,
        300
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "b17352d9-135a-4c26-993f-0c1fdafc1fa3",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1420,
        300
      ],
      "parameters": {
        "width": 394.2691415313225,
        "height": 159.80531276753783,
        "content": "## Preparation\nThis line is responsible for taking data from email and parsing it into JSON understandable by n8n"
      },
      "typeVersion": 1
    },
    {
      "id": "31d2f822-aea6-41b4-bb1e-25b48cb3e972",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1420,
        500
      ],
      "parameters": {
        "width": 394.2691415313225,
        "height": 316.3177609714967,
        "content": "## Mapping\nThis line is responsible for treating cases when XML has multiple info for domain. One DMARC report can contain more than one entries.\n\nLast node is responsible for matching data with database structure"
      },
      "typeVersion": 1
    },
    {
      "id": "e8fc0f91-1bdf-4bc5-b488-4f2c169da9c0",
      "name": "Split Out For Separate Entries",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        800,
        500
      ],
      "parameters": {
        "include": "allOtherFields",
        "options": {},
        "fieldToSplitOut": "feedback.record"
      },
      "typeVersion": 1
    },
    {
      "id": "9ba7a0b8-80e6-4559-83ec-894533194dc7",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1420,
        860
      ],
      "parameters": {
        "width": 394.2691415313225,
        "height": 185.89072080153096,
        "content": "## Date translate\nThis line is responsible for translating date format into understandable by MySQL/MariaDB\n\nIn next node data is being input into MySQL/MariaDB "
      },
      "typeVersion": 1
    },
    {
      "id": "96461e30-87f0-48f1-a43f-60185ea1d835",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1420,
        1180
      ],
      "parameters": {
        "width": 394.2691415313225,
        "height": 320.66532897716223,
        "content": "## Notifications\nLast two nodes are responsible for sending notifications in case IF inside DMARC report is reported any issue with SPF or DKIM"
      },
      "typeVersion": 1
    },
    {
      "id": "192b95c6-cdfe-4b5e-94e1-94deb728b0e2",
      "name": "Slack Post Message On Channel",
      "type": "n8n-nodes-base.slack",
      "disabled": true,
      "position": [
        1200,
        1180
      ],
      "parameters": {
        "text": "=DMARC evaluation failed for {{ $json.domain }} on  {{ $json.mail_count }} mails with disposition:  {{ $json.evaluated_disposition }}. DKIM:  {{ $json.evaluated_dkim }} SPF:  {{ $json.evaluated_spf }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "CCGJA1F1N",
          "cachedResultName": "powiadomienia"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "ce400c97-cae4-41db-ad8f-e678fc4a27fe",
      "name": "Send Error Notification Email",
      "type": "n8n-nodes-base.emailSend",
      "disabled": true,
      "position": [
        1200,
        1380
      ],
      "parameters": {
        "text": "DMARC evaluation failed for {{ $json.domain }} on  {{ $json.mail_count }} mails with disposition:  {{ $json.evaluated_disposition }}. DKIM:  {{ $json.evaluated_dkim }} SPF:  {{ $json.evaluated_spf }}",
        "options": {},
        "subject": "DMARC problem",
        "emailFormat": "text"
      },
      "typeVersion": 2.1
    }
  ],
  "active": true,
  "settings": {
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": "5",
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "saveExecutionProgress": true,
    "saveDataSuccessExecution": "all"
  },
  "versionId": "1add308c-4aef-4a83-a958-bc66dead234f",
  "connections": {
    "Unzip File": {
      "main": [
        [
          {
            "node": "Extract XML data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rename Keys": {
      "main": [
        [
          {
            "node": "Map fields for DB input and parse",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "End date format": {
      "main": [
        [
          {
            "node": "Input into database",
            "type": "main",
            "index": 0
          },
          {
            "node": "If issue with DKIM or SPF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract XML data": {
      "main": [
        [
          {
            "node": "Parse XML data to JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Begin format date": {
      "main": [
        [
          {
            "node": "End date format",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email Trigger (IMAP)": {
      "main": [
        [
          {
            "node": "Unzip File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse XML data to JSON": {
      "main": [
        [
          {
            "node": "If multiple records to parse",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If issue with DKIM or SPF": {
      "main": [
        [
          {
            "node": "Slack Post Message On Channel",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send Error Notification Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If multiple records to parse": {
      "main": [
        [
          {
            "node": "Split Out For Separate Entries",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Rename column for consistency",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rename column for consistency": {
      "main": [
        [
          {
            "node": "Map fields for DB input and parse",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out For Separate Entries": {
      "main": [
        [
          {
            "node": "Rename Keys",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Map fields for DB input and parse": {
      "main": [
        [
          {
            "node": "Begin format date",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

If you are a postmaster or you manage email server, you can set up DKIM and SPF records to ensure that spoofing your email address is hard. On your domain you can also set up DMARC record to receive XML reports from email providers (rua tag). Those reports contain data if email…

Source: https://n8n.io/workflows/2369/ — original creator credit. Request a take-down →

More Email & Gmail workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Email & Gmail

Nathan is a proof of concept framework for creating a personal assistant who can handle various day to day functions for you.

Email Read Imap, Read Binary File, Spreadsheet File +2
Email & Gmail

New invoice email notification. Uses emailReadImap, mindee, slack, emailSend. Manual trigger; 6 nodes.

Email Read Imap, Mindee, Slack +1
Email & Gmail

This workflow checks for new emails in a mailbox and if the email body contains the word "invoice" it will send the attachment to Mindee. It then posts a message to Slack to let the team know a paymen

Email Read Imap, Mindee, Slack +1
Email & Gmail

Transform your customer support operations with this enterprise-grade automation workflow that unifies, categorizes, and intelligently routes support tickets from multiple channels.

Email Read Imap, Email Send, Slack +1
Email & Gmail

This automated n8n workflow automates AWS S3 bucket and file operations (create, delete, upload, download, copy, list) by parsing simple email commands and sending back success or error confirmations.

Email Read Imap, AWS S3, Email Send