{
  "id": "WrlMDVogrh8Ddavr",
  "name": "AI salutation generator for email messaging via OpenAI and KlickTipp",
  "tags": [],
  "nodes": [
    {
      "id": "8fb4d696-99f4-407b-8608-f0f9d94e4be1",
      "name": "Structured Output Parser1",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1152,
        304
      ],
      "parameters": {
        "jsonSchemaExample": "{\n    \"salutation\": \"\",\n    \"salutation_quality\": 0,\n    \"style\": \"formal/informal\",\n    \"language\": \"de/en\",\n    \"signoff_type\": \"team/personal\",\n    \"reason\": \"\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "8cde79d0-4a59-463a-aece-d4cfcd287b47",
      "name": "OpenAI Chat Model1",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        976,
        304
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5-mini",
          "cachedResultName": "gpt-5-mini"
        },
        "options": {}
      },
      "credentials": {},
      "typeVersion": 1.2
    },
    {
      "id": "7a51b10e-4f31-4ae9-b419-29fa7872baab",
      "name": "Contact Tagged in KlickTipp",
      "type": "n8n-nodes-klicktipp.klicktippTrigger",
      "position": [
        768,
        80
      ],
      "parameters": {},
      "credentials": {},
      "typeVersion": 1
    },
    {
      "id": "338e60e0-c082-4492-886f-89bcbf793fa1",
      "name": "Generate a salutation",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        992,
        80
      ],
      "parameters": {
        "text": "=Process this contact information:\n- First name: {{ $json.fieldFirstName }}\n- Last name: {{$json.fieldLastName}}\n- Email: {{$json.email}}\n- Company name: {{$json.fieldCompanyName}}\n- Street 1: {{$json.fieldStreet1}}\n- Street 2: {{$json.fieldStreet2}}\n- City: {{$json.fieldCity}}\n- State: {{$json.fieldState}}\n- Zip: {{$json.fieldZip}}\n- Country: {{$json.fieldCountry}}\n- Website: {{$json.fieldWebsite}}\n- Birthday: {{$json.fieldBirthday}}",
        "options": {
          "systemMessage": "=**Role / Context**  \nYou generate an email salutation (the formal header / opening line) for KlickTipp contacts.\n\nDefinition: a salutation is the written opening address line at the start of an email/letter (e.g., \"Dear [Name],\", \"Guten Tag Herr M\u00fcller,\").\n\n---\n\n**Task / Goal**  \n\nCreate a reusable, HTML-ready email salutation based on contact information below.\n\nReturn ONLY valid JSON that matches the provided schema. No extra text.\n\n---\n\n**Constraints / Rules**  \n\n- salutation_html: ONE short HTML string. No <p> tags. You may use <br /> only if needed (prefer no <br />). Always end with a comma.\n- salutation_quality: integer 0\u2013100 indicating how appropriate and safe the salutation is.\n- style: \"formal\" or \"informal\".\n- language: \"de\" or \"en\".\n- address_basis: \"full_name\" | \"first_name\" | \"last_name\" | \"email_only\" | \"generic\"\n- reason: short internal note if quality is low.\n\nDecision rules:\n1) Determine language:\n   - If Country suggests Germany/Austria/Switzerland OR the data looks German -> language=\"de\"\n   - Otherwise default to language=\"en\"\n\n2) Determine style (distance):\n   - If Company name exists OR Website exists OR address fields clearly indicate business -> prefer style=\"formal\"\n   - Otherwise style=\"informal\"\n   - If First name exists and looks like a real person -> informal is allowed, but formal is still acceptable for business contexts.\n\n3) Choose the best salutation (in this priority order):\n   A) If language=\"de\" AND style=\"formal\":\n      - If Last name exists: \"Guten Tag {{$json.fieldLastName}},\"\n      - If only First name exists: \"Guten Tag {{$json.fieldFirstName}},\"\n      - If no usable name: \"Guten Tag,\"\n   B) If language=\"de\" AND style=\"informal\":\n      - If First name exists: \"Hallo {{$json.fieldFirstName}},\"\n      - Else if Last name exists: \"Hallo {{$json.fieldLastName}},\"\n      - Else: \"Hallo,\"\n   C) If language=\"en\" AND style=\"formal\":\n      - If Last name exists: \"Dear {{$json.fieldLastName}},\"\n      - If only First name exists: \"Dear {{$json.fieldFirstName}},\"\n      - Else: \"Dear Sir or Madam,\"\n   D) If language=\"en\" AND style=\"informal\":\n      - If First name exists: \"Hi {{$json.fieldFirstName}},\"\n      - Else: \"Hi,\"\n\n4) Important constraints:\n- Do NOT guess titles (Mr/Ms/Dr) unless explicitly provided in the input (we don't have it here, so don't use them).\n- Do NOT infer gender from first/last name for formal titles.\n- Do NOT include the company name in the salutation.\n- Do NOT mention any private contact details (address, birthday, email) in the salutation.\n- Keep it short and conventional.\n\n5) salutation_quality scoring:\n- 95\u2013100: clear name + appropriate style + clear language\n- 80\u201394: good guess but minor ambiguity\n- 50\u201379: name missing or language unclear -> generic safe salutation\n- <50: contact looks like a system mailbox (info@, support@, noreply@) -> generic formal with low score"
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 2.1
    },
    {
      "id": "ce062f3d-3cf9-421f-8490-15e424e51670",
      "name": "Update Contact in KlickTipp",
      "type": "n8n-nodes-klicktipp.klicktipp",
      "position": [
        1600,
        80
      ],
      "parameters": {
        "fields": {
          "dataFields": [
            {
              "fieldId": "field228722",
              "fieldValue": "={{ $json.output.salutation }}"
            }
          ]
        },
        "resource": "subscriber",
        "operation": "update",
        "subscriberId": "={{ $('Contact Tagged in KlickTipp').item.json.id }}",
        "identifierType": "id"
      },
      "credentials": {},
      "typeVersion": 3
    },
    {
      "id": "e59c503f-3794-44d8-9f13-fcfcefa6a39a",
      "name": "Salutation quality >= 80% ?",
      "type": "n8n-nodes-base.filter",
      "position": [
        1360,
        80
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "9f2f1911-5417-494b-b07c-1499d8ea4c19",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.output.salutation_quality }}",
              "rightValue": 80
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "ced2f9f6-52a6-4d7f-b652-3aa6d095f0cd",
      "name": "Documentation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -16,
        -48
      ],
      "parameters": {
        "width": 695,
        "height": 764,
        "content": "Community Node Disclaimer: This workflow uses KlickTipp community nodes.\n\n## Introduction\nThis workflow automatically generates a personalized **email salutation** for KlickTipp contacts using **OpenAI**, and stores it as a reusable KlickTipp custom field. When a contact is tagged, the workflow creates a suitable salutation such as **\u201cGuten Tag M\u00fcller,\u201d**, **\u201cHallo Ren\u00e9,\u201d**, or a safe fallback like **\u201cGuten Tag,\u201d** when data is incomplete. It also returns a **salutation quality score (0\u2013100)** to help you decide whether the result is reliable enough to store and reuse.\n\nThis automation is especially useful for marketers, coaches, creators, agencies, and service-based businesses who want consistent personalization at scale, while keeping messaging professional through confidence-based fallbacks and reducing the need for manual contact cleanup.\n\n## How it works\n1. **Trigger: Contact tagged in KlickTipp** (e.g., `HTML AI salutation for email messaging`)\n2. **OpenAI: Generate a salutation** using available contact data (name, email, company, location)\n3. **Filter: salutation_quality >= 80** (adjustable threshold)\n4. **Update contact in KlickTipp** by saving found **salutation**\n\n## Setup Instructions\n1. **KlickTipp preparation**\n   - Create a trigger **tag** (e.g., `HTML AI salutation for email messaging`)\n   - Create **custom field**:\n     - **HTML AI placeholders | salutation**\n   - Add **webhook**:\n     - **Activation tag:** `HTML AI salutation for email messaging`\n     - **Activation URL:** webhook URL from triggers\n\n2. **Credential Configuration**\n     - Authenticate your KlickTipp connection with **username/password** credentials (API access required).\n     - Connect your OpenAI account using a **API Key** .\n\n## Customization\n- **Threshold**: increase (stricter) or decrease (more coverage)\n- **Tone/language**: enforce in the OpenAI prompt if you want consistent output"
      },
      "typeVersion": 1
    },
    {
      "id": "3a88d88f-5f15-4ccb-ace6-e70deec5170e",
      "name": "1. Trigger from a KlickTipp",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        688,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 232,
        "height": 524,
        "content": "## 1. Trigger from a KlickTipp"
      },
      "typeVersion": 1
    },
    {
      "id": "73ee5879-7c2c-4bb9-8678-f9c4f74c755a",
      "name": "2. Generate salutation via OpenAI",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 360,
        "height": 524,
        "content": "## 2. Generate salutation via OpenAI"
      },
      "typeVersion": 1
    },
    {
      "id": "a282ad31-0793-4c1d-84a7-6cf8cd8194a3",
      "name": "3. Filter results",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1296,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 232,
        "height": 524,
        "content": "## 3. Filter results"
      },
      "typeVersion": 1
    },
    {
      "id": "9da0ed4e-bd9d-4e89-9db4-4f2dc00d9c6b",
      "name": "4. Update contact with salutation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1536,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 232,
        "height": 524,
        "content": "## 4. Update contact with salutation"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "d1b8193e-ccfb-4c4d-88cb-563946097187",
  "nodeGroups": [],
  "connections": {
    "OpenAI Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Generate a salutation",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Generate a salutation": {
      "main": [
        [
          {
            "node": "Salutation quality >= 80% ?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser1": {
      "ai_outputParser": [
        [
          {
            "node": "Generate a salutation",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Contact Tagged in KlickTipp": {
      "main": [
        [
          {
            "node": "Generate a salutation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Salutation quality >= 80% ?": {
      "main": [
        [
          {
            "node": "Update Contact in KlickTipp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}