AutomationFlowsEmail & Gmail › Generate & Validate Utility Certificates

Generate & Validate Utility Certificates

Original n8n title: Utility-certificate-creator&validation

6-Utility-Certificate-Creator&Validation. Uses dataTable, @pdfgeneratorapi/n8n-nodes-pdf-generator-api, gmail, respondToWebhook. Webhook trigger; 19 nodes.

Webhook trigger★★★★☆ complexity19 nodesData Table@Pdfgeneratorapi/N8N Nodes Pdf Generator ApiGmail
Email & Gmail Trigger: Webhook Nodes: 19 Complexity: ★★★★☆ Added:
Generate & Validate Utility Certificates — n8n workflow card showing Data Table, @Pdfgeneratorapi/N8N Nodes Pdf Generator Api, Gmail integration

This workflow follows the Datatable → Gmail 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": "o018cyB8genb6ONB",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "6-Utility-Certificate-Creator&Validation",
  "tags": [
    {
      "id": "YOUR-ID",
      "name": "YOUR-ID",
      "createdAt": "2025-11-23T13:36:13.729Z",
      "updatedAt": "2025-11-23T13:36:13.729Z"
    }
  ],
  "nodes": [
    {
      "id": "613c5389-2f80-44c9-8ec1-043d02d720d7",
      "name": "Insert_Certificaton",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        320,
        -224
      ],
      "parameters": {
        "columns": {
          "value": {
            "Name": "={{ $('Webhook_Creation').item.json.headers.name }}",
            "Surname": "={{ $('Webhook_Creation').item.json.headers.surname }}",
            "CertificationID": "={{ $('Generate_Certification_ID').item.json.id }}"
          },
          "schema": [
            {
              "id": "Name",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Name",
              "defaultMatch": false
            },
            {
              "id": "Surname",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Surname",
              "defaultMatch": false
            },
            {
              "id": "CertificationID",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "CertificationID",
              "defaultMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "Your_ID",
          "cachedResultUrl": "/projects/jmCdsRSQMosgYP5V/datatables/Your_ID",
          "cachedResultName": "Certifications"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "7b690565-bc2e-4c50-9e34-5368972be90f",
      "name": "Generate_Certification_ID",
      "type": "n8n-nodes-base.code",
      "position": [
        -352,
        -240
      ],
      "parameters": {
        "jsCode": "const uniqueId =\n  Date.now().toString(36).toUpperCase() +\n  Math.random().toString(36).substring(2, 8).toUpperCase();\n\nreturn [{ id: uniqueId }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "ee3e5ab4-7d0a-41d9-b72c-0d1e071c9142",
      "name": "Find_Certification_By_ID",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        -144,
        -240
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "CertificationID",
              "keyValue": "={{ $json.id }}"
            }
          ]
        },
        "operation": "get",
        "returnAll": true,
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "ZyOrfuHDK22tXq81",
          "cachedResultUrl": "/projects/YOUR_ID/datatables/ZyOrfuHDK22tXq81",
          "cachedResultName": "Certifications"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "554946dd-0444-4e50-b132-983b44e931e5",
      "name": "Certification_ID_Exists",
      "type": "n8n-nodes-base.if",
      "position": [
        64,
        -240
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "416a8c8a-b9bd-4044-9987-b3320c09efd4",
              "operator": {
                "type": "string",
                "operation": "empty",
                "singleValue": true
              },
              "leftValue": "=Object",
              "rightValue": "={{ $json }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "848bddc2-4362-40b6-a8e0-18511f9b5c23",
      "name": "Generate_PDF",
      "type": "@pdfgeneratorapi/n8n-nodes-pdf-generator-api.pdfGeneratorApi",
      "position": [
        528,
        -224
      ],
      "parameters": {
        "resource": "conversion",
        "htmlContent": "=<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Certificate of Achievement</title>\n</head>\n<body>\n\n<div style=\"\n    width: 800px;\n    height: 600px;\n    margin: 50px auto;\n    padding: 30px;\n    border: 10px solid #0056b3; /* Dark blue main border */\n    border-image: linear-gradient(45deg, #0056b3, #007bff, #0056b3) 1; /* Gradient effect */\n    box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);\n    background-color: #ffffff; /* White background for clean look */\n    font-family: 'Arial', sans-serif; /* Simplified font for better rendering */\n    text-align: center;\n    position: relative;\n\">\n    \n    <h1 style=\"\n        font-size: 48px;\n        color: #e3a800; /* Gold/Orange */\n        margin-bottom: 0;\n        text-transform: uppercase;\n        letter-spacing: 3px;\n    \">CERTIFICATE</h1>\n    \n    <h2 style=\"\n        font-size: 36px;\n        color: #0056b3; /* Dark Blue */\n        margin-top: 5px;\n        margin-bottom: 40px;\n        text-transform: uppercase;\n    \">OF ACHIEVEMENT</h2>\n    \n    <p style=\"\n        font-size: 18px;\n        color: #343a40;\n        margin-bottom: 10px;\n        font-style: italic;\n    \">Is proudly presented to:</p>\n    \n    <div style=\"\n        border-bottom: 2px solid #343a40;\n        display: inline-block;\n        padding: 5px 60px;\n        margin-bottom: 40px;\n    \">\n        <p style=\"\n            font-size: 36px;\n            color: #000000;\n            font-weight: bold;\n            text-transform: uppercase;\n            letter-spacing: 1px;\n            margin: 0;\n        \">{{ $('Webhook_Creation').item.json.headers.name }}&nbsp;{{ $('Webhook_Creation').item.json.headers.surname }}</p> \n    </div>\n    \n    <p style=\"\n        font-size: 24px;\n        color: #343a40;\n        line-height: 1.5;\n        margin-bottom: 80px; /* Increased margin for signature lines */\n    \">\n        For successful completion and outstanding performance in the course:\n        <br>\n        <strong style=\"color: #007bff; font-size: 30px;\">\"{{ $('Webhook_Creation').item.json.headers.course }}\"</strong>\n    </p>\n    \n    <div style=\"\n        display: flex;\n        justify-content: space-around;\n        align-items: flex-end;\n        width: 80%;\n        margin: 0 auto;\n    \">\n        \n        <div style=\"text-align: center; flex-basis: 40%;\">\n            <p style=\"\n                font-size: 16px; \n                font-weight: bold; \n                margin: 0 0 5px 0;\n                color: #000000;\n                letter-spacing: 0.5px;\n            \">\n                {{ $('Generate_Certification_ID').item.json.id }}\n            </p>\n            <div style=\"border-top: 1px solid #343a40; width: 100%;\"></div>\n            <p style=\"margin: 5px 0 0 0; font-size: 14px; color: #343a40;\">\n                Candidate ID\n            </p>\n        </div>\n        \n        <div style=\"text-align: center; flex-basis: 40%;\">\n            <p style=\"\n                font-size: 16px; \n                font-weight: bold; \n                margin: 0 0 5px 0;\n                color: #000000;\n                letter-spacing: 0.5px;\n            \">\n                {{ $today.toFormat('dd/MM/yyyy') }}\n            </p>\n            <div style=\"border-top: 1px solid #343a40; width: 100%;\"></div>\n            <p style=\"margin: 5px 0 0 0; font-size: 14px; color: #343a40;\">\n                Date\n            </p>\n        </div>\n        \n    </div>\n\n</div>\n\n</body>\n</html>",
        "conversionOptions": {
          "orientation": "landscape",
          "conversionOutput": "file"
        }
      },
      "credentials": {
        "pdfGeneratorApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "03f873c2-f9b0-409c-bff0-4d32f5ed6efd",
      "name": "Email_Certification",
      "type": "n8n-nodes-base.gmail",
      "position": [
        752,
        -224
      ],
      "parameters": {
        "sendTo": "={{ $('Webhook_Creation').item.json.headers.email }}",
        "message": "Attached you find your new certification!",
        "options": {
          "attachmentsUi": {
            "attachmentsBinary": [
              {
                "property": "document.pdf"
              }
            ]
          }
        },
        "subject": "Your certification is ready!"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "aed81c3b-10ce-4d98-9b6c-c890c71ab815",
      "name": "Webhook_Check",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -592,
        224
      ],
      "parameters": {
        "path": "certificationscheck",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "71b9f653-4574-4bf2-b9ce-660c083d0a85",
      "name": "Find_Certification_By_ID1",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        -352,
        224
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "CertificationID",
              "keyValue": "={{ $json.headers.id }}"
            }
          ]
        },
        "operation": "get",
        "returnAll": true,
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "ZyOrfuHDK22tXq81",
          "cachedResultUrl": "/projects/jmCdsRSQMosgYP5V/datatables/ZyOrfuHDK22tXq81",
          "cachedResultName": "Certifications"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "e35823bf-189c-4192-85ca-24010ba3ed09",
      "name": "Certification_Exists",
      "type": "n8n-nodes-base.if",
      "position": [
        -144,
        224
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "416a8c8a-b9bd-4044-9987-b3320c09efd4",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.CertificationID }}",
              "rightValue": "={{ $('Webhook_Check').item.json.headers.id }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "98428e2a-330b-4995-b177-74ce6ec41a35",
      "name": "Respond_Found",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        96,
        160
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={\n  \"ok\": \"true\",\n  \"name\": \"{{ $('Find_Certification_By_ID1').item.json.Name }}\",\n  \"surname\": \"{{ $('Find_Certification_By_ID1').item.json.Surname }}\"\n}"
      },
      "typeVersion": 1.4
    },
    {
      "id": "15e115bd-3d35-4805-9806-85d6e80a7c21",
      "name": "Respond_NotFound",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        96,
        288
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "{\n  \"ok\": \"false\"\n}"
      },
      "typeVersion": 1.4
    },
    {
      "id": "38d50087-20f5-43aa-acbd-0893dafe8381",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -672,
        -448
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 368,
        "content": "## Creation  \n## Webhook input\n\nReceives name, surname, course and email via HTTP POST on `/certifications`.  \nStarts the certificate creation flow.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "9672b65b-832d-4496-9f50-d75b5432fcc2",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -400,
        -448
      ],
      "parameters": {
        "color": 7,
        "width": 864,
        "height": 368,
        "content": "## Creation \u2013 Generate & validate ID\n\nGenerates a random CertificationID, checks the Data Table for duplicates and only continues when the ID is unique.  \nIf the ID already exists, the flow loops until a free one is found.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "00c13ad1-1026-4b0f-b880-89d901a1ee11",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        -448
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 368,
        "content": "## Creation \u2013 Save, PDF & email\n\nSaves the learner record with the CertificationID to the Data Table, generates the certificate PDF from an HTML template and emails it to the learner.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "741f9beb-f922-441b-9249-c6a06da55571",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -672,
        32
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 320,
        "content": "## Check \u2013 Webhook input\n\nReceives a CertificationID via HTTP POST on `/certificationscheck` and starts the verification flow.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "1c7f6487-80e4-45d2-a676-645f66c4bfaf",
      "name": "Webhook_Creation",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -592,
        -240
      ],
      "parameters": {
        "path": "certifications",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "lastNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "28750e3a-7cec-4a45-8a5a-cb87dbd3181d",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -400,
        32
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 320,
        "content": "## Check \u2013 Look up ID\n\nSearches the Certifications Data Table for the submitted CertificationID and branches depending on whether a matching record exists.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "18468a33-fdb7-4602-a995-29d9e1c5aca5",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        272,
        176
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 176,
        "content": "## Check \u2013 Responses\n\nReturns JSON to the caller.  \nIf the ID is found: `ok: true` plus name and surname.  \nIf not found: `ok: false` so the client can show an \u201cinvalid certification\u201d message.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "3bedbbcb-cd61-4c54-872d-cfd54df9e991",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1344,
        -448
      ],
      "parameters": {
        "width": 640,
        "height": 560,
        "content": "## Certifications \u2013 Creator & Checker\n\n## How it works\nThis workflow manages the full lifecycle of a training certificate.  \n`/certifications` receives learner details, generates a unique CertificationID and checks that it does not exist yet.  \nIf the ID is free, the workflow stores the record, builds a PDF certificate and emails it to the learner.  \n\n`/certificationscheck` lets you verify a certificate later.  \nThe webhook receives a CertificationID, looks it up in the same Data Table and returns a simple JSON response that frontends or other services can use to show \u201cvalid\u201d or \u201cnot found\u201d.\n\n## Setup steps\n1. Create a Data Table (e.g. **Certifications**) with Name, Surname, CertificationID and any extra fields.\n2. Configure the PDF Generator node with your account API and adjust the HTML template to your branding.\n3. Connect your email account (Gmail/SMTP) in **Email_Certification**.\n4. Deploy the `/certifications` and `/certificationscheck` webhooks and use their public URLs.\n5. Test creation and verification with a few sample requests before going live.\n"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "898197be-08ab-4488-85ee-a9a1b688cb1c",
  "connections": {
    "Generate_PDF": {
      "main": [
        [
          {
            "node": "Email_Certification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook_Check": {
      "main": [
        [
          {
            "node": "Find_Certification_By_ID1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook_Creation": {
      "main": [
        [
          {
            "node": "Generate_Certification_ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Insert_Certificaton": {
      "main": [
        [
          {
            "node": "Generate_PDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Certification_Exists": {
      "main": [
        [
          {
            "node": "Respond_Found",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond_NotFound",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Certification_ID_Exists": {
      "main": [
        [
          {
            "node": "Generate_Certification_ID",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Insert_Certificaton",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find_Certification_By_ID": {
      "main": [
        [
          {
            "node": "Certification_ID_Exists",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find_Certification_By_ID1": {
      "main": [
        [
          {
            "node": "Certification_Exists",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate_Certification_ID": {
      "main": [
        [
          {
            "node": "Find_Certification_By_ID",
            "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

How this works

This workflow streamlines the creation and validation of utility certificates by generating unique IDs, producing personalised PDFs, and sending them via email, saving hours of manual document handling for small business owners or administrators managing compliance records. It suits those needing quick, verifiable certificates without complex software, integrating seamlessly with DataTable for storage and PDF Generator API for professional outputs. The key step involves checking if a certificate ID already exists in the database before proceeding to PDF creation and Gmail dispatch, ensuring accuracy and preventing duplicates.

Use this workflow when handling routine certificate requests triggered by webhooks, such as customer verifications or service confirmations, to automate end-to-end processing efficiently. Avoid it for high-volume operations requiring advanced security like digital signatures, or when certificates need integration with enterprise systems beyond basic email and database functions. Common variations include adapting the DataTable schema for different certificate types or adding conditional logic for custom email templates based on user roles.

About this workflow

6-Utility-Certificate-Creator&Validation. Uses dataTable, @pdfgeneratorapi/n8n-nodes-pdf-generator-api, gmail, respondToWebhook. Webhook trigger; 19 nodes.

Source: https://github.com/paoloronco/n8n-templates/blob/main/free-templates/3-Certification-Creation&Validation/Cetificate-Creation&Validation.json — 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

A complete workflow to create, send, and verify digital certificates fully automated with n8n.Perfect for courses, events, onboarding, internal training, or product education.

Data Table, @Pdfgeneratorapi/N8N Nodes Pdf Generator Api, Gmail
Email & Gmail

This n8n workflow provides a complete end-to-end system for creating, distributing, and verifying digital certificates, using PDF Generator API templates instead of raw HTML.

Data Table, Gmail, @Pdfgeneratorapi/N8N Nodes Pdf Generator Api
Email & Gmail

Automate WhatsApp communication for recruitment agencies with an interactive, structured customer experience. This workflow handles pricing inquiries, request submissions, tracking, complaints, and hu

HTTP Request, Google Sheets, Gmail +1
Email & Gmail

Creating and sending invoices manually is a major administrative bottleneck. It's not only slow but also prone to human error, such as creating duplicate invoice numbers or sending sensitive financial

Google Sheets, @Pdfgeneratorapi/N8N Nodes Pdf Generator Api, Google Drive +1
Email & Gmail

Svyatobor_Bot. Uses dataTable, telegram, gmail. Webhook trigger; 4 nodes.

Data Table, Telegram, Gmail