AutomationFlowsGeneral › Contact Memory Update

Contact Memory Update

Contact-Memory-Update. Uses executeWorkflowTrigger, googleDrive, lmChatGroq, chainLlm. Event-driven trigger; 14 nodes.

Event trigger★★★★☆ complexityAI-powered14 nodesExecute Workflow TriggerGoogle DriveGroq ChatChain Llm
General Trigger: Event Nodes: 14 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow follows the Chainllm → Execute Workflow Trigger 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
{
  "nodes": [
    {
      "parameters": {
        "content": "# Contact Email Store\n\nStores email as .md file in contact's emails/ folder and updates README.md profile via LLM.\n\n**Inputs:**\n- emails_folder_id: Target folder for email storage\n- folder_id: Contact folder (for README)\n- email_subject, body_core: Email content\n- contact_name, contact_email: Contact info (the other party)",
        "height": 240,
        "width": 400
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4048,
        2944
      ],
      "typeVersion": 1,
      "id": "2f632337-594b-4058-ad9d-8bd231539a3c",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "inputSource": "passthrough"
      },
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.1,
      "position": [
        4528,
        2976
      ],
      "id": "37bcbe68-f8aa-4c80-a2bc-b74aeafb40ca",
      "name": "When Executed by Another Workflow"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        4528,
        2784
      ],
      "id": "134827e6-f9a5-43f9-a2b3-03fa2393cb04",
      "name": "Manual Trigger"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "emails-folder-id",
              "name": "emails_folder_id",
              "value": "={{ $json.emails_folder_id }}",
              "type": "string"
            },
            {
              "id": "folder-id",
              "name": "folder_id",
              "value": "={{ $json.folder_id }}",
              "type": "string"
            },
            {
              "id": "email-subject",
              "name": "email_subject",
              "value": "={{ $json.email_subject || 'No Subject' }}",
              "type": "string"
            },
            {
              "id": "email-body",
              "name": "body_core",
              "value": "={{ $json.body_core || '' }}",
              "type": "string"
            },
            {
              "id": "sender-name",
              "name": "contact_name",
              "value": "={{ $json.contact_name || '' }}",
              "type": "string"
            },
            {
              "id": "sender-email",
              "name": "contact_email",
              "value": "={{ $json.contact_email || '' }}",
              "type": "string"
            },
            {
              "id": "email-date",
              "name": "email_date",
              "value": "={{ $now.toISO() }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        4752,
        2880
      ],
      "id": "b0b3beae-8db4-4f45-b84e-ba0ceafd40e7",
      "name": "Prepare Input"
    },
    {
      "parameters": {
        "jsCode": "// Build email file with YAML frontmatter and ISO datetime filename\nconst input = $input.first().json;\n\n// ISO datetime for filename (replace colons with dashes for filesystem)\nconst isoDate = input.email_date.replace(/:/g, '-').split('.')[0];\nconst subjectSlug = input.email_subject\n  .toLowerCase()\n  .replace(/[^a-z0-9]+/g, '-')\n  .replace(/^-|-$/g, '')\n  .substring(0, 50);\nconst filename = `${isoDate}_${subjectSlug}.md`;\n\n// Build file content with YAML frontmatter\nconst directionLabel = input.direction === 'outbound' ? 'to' : 'from';\nconst fileContent = `---\nname: Email-${input.email_subject}\ndate: ${input.email_date}\ndirection: ${input.direction}\n${directionLabel}: ${input.contact_email}\n---\n\n${input.body_core}\n`;\n\n// Create binary data for upload\nconst binaryData = Buffer.from(fileContent, 'utf8').toString('base64');\n\nreturn [{\n  json: {\n    ...input,\n    filename: filename\n  },\n  binary: {\n    data: {\n      data: binaryData,\n      mimeType: 'text/markdown',\n      fileName: filename\n    }\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        4976,
        2880
      ],
      "id": "0257dc8b-ac3e-4896-b2de-829fea8385ff",
      "name": "Prepare Email File"
    },
    {
      "parameters": {
        "name": "={{ $json.filename }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "folderId": {
          "__rl": true,
          "value": "={{ $json.emails_folder_id }}",
          "mode": "id"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        5200,
        2880
      ],
      "id": "02b04ee4-14d3-4b8d-9e67-f4ca5395989a",
      "name": "Upload Email File",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "fileFolder",
        "searchMethod": "query",
        "limit": 1,
        "filter": {
          "folderId": {
            "__rl": true,
            "value": "={{ $('Prepare Input').first().json.folder_id }}",
            "mode": "id"
          },
          "whatToSearch": "files"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        5424,
        2880
      ],
      "id": "8749aa8a-4c4c-4935-94af-67ac2a1712e6",
      "name": "Find README",
      "alwaysOutputData": true,
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": {
          "__rl": true,
          "value": "={{ $json.id }}",
          "mode": "id"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        5648,
        2880
      ],
      "id": "50a58c20-dcb4-4182-bd45-171648a99d1a",
      "name": "Download README",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Extract README content from binary\nconst item = $input.first();\nconst binaryData = item.binary?.data;\nlet currentContent = '';\n\nif (binaryData) {\n  currentContent = Buffer.from(binaryData.data, 'base64').toString('utf8');\n}\n\nconst inputData = $('Prepare Input').first().json;\n\nreturn [{\n  json: {\n    readme_id: $('Find README').first().json.id,\n    readme_content: currentContent,\n    email_subject: inputData.email_subject,\n    body_core: inputData.body_core,\n    email_date: inputData.email_date,\n    contact_name: inputData.contact_name,\n    contact_email: inputData.contact_email,\n    direction: inputData.direction,\n    owner_name: inputData.owner_name\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        4752,
        3072
      ],
      "id": "14f43567-49a1-45b7-aafc-b373c786bbcb",
      "name": "Prep LLM Input"
    },
    {
      "parameters": {
        "model": "openai/gpt-oss-120b",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGroq",
      "typeVersion": 1,
      "position": [
        4976,
        3280
      ],
      "id": "1c4f8460-ddde-4efd-9043-a0953805e480",
      "name": "Profile LLM",
      "credentials": {
        "groqApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=You are managing the contact profiles for {{ $json.owner_name }}. Your task is to maintain a concise biographical profile of each contact.\n\n{{ $json.direction === 'outbound' ? 'CONTEXT: ' + $json.owner_name + ' SENT this email TO' : 'CONTEXT: ' + $json.owner_name + ' RECEIVED this email FROM' }} {{ $json.contact_name }} <{{ $json.contact_email }}>.\n\nRULES:\n1. Output ONLY plain text - NO YAML frontmatter (the system adds it automatically)\n2. Write 2-4 sentences about WHO THIS CONTACT IS (their company, role, what they do)\n3. If contact is a company/service (e.g. Railway, Stripe, AWS), describe what that company does\n4. DO NOT describe {{ $json.owner_name }} or their actions - only describe the contact\n5. DO NOT include operational details (support instructions, account changes, action items)\n6. Focus on durable facts: what company/person is this, what do they do, why might {{ $json.owner_name }} interact with them\n7. Merge new information with existing profile, update outdated info\n\n---\n\n## Current Profile:\n{{ $json.readme_content }}\n\n## {{ $json.direction === 'outbound' ? $json.owner_name + ' sent email TO' : 'Email FROM' }} {{ $json.contact_name }} <{{ $json.contact_email }}> ({{ $json.email_date }}):\nSubject: {{ $json.email_subject }}\n\n{{ $json.body_core }}\n\n---\nOutput ONLY a biographical profile of the contact (2-4 sentences, no YAML):",
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.7,
      "position": [
        4976,
        3072
      ],
      "id": "ee9a06ed-a862-4ee0-bc30-dd57e92f8088",
      "name": "LLM: Update Profile"
    },
    {
      "parameters": {
        "jsCode": "// Prepare updated README for upload\nconst llmOutput = $input.first().json.text || $input.first().json.output || '';\nconst readmeId = $('Prep LLM Input').first().json.readme_id;\n\n// Strip any YAML the LLM might have generated and get plain text only\nlet bioContent = llmOutput.trim();\n\n// Remove YAML frontmatter if LLM included it (it shouldn't, but safety check)\nif (bioContent.startsWith('---')) {\n  const endMarker = bioContent.indexOf('---', 3);\n  if (endMarker !== -1) {\n    bioContent = bioContent.substring(endMarker + 3).trim();\n  }\n}\n\n// Always use the fixed header\nconst fixedHeader = `---\\nname: ContactManager-Record\\ndescription: Most salient summary of the person that contacted me.\\n---\\n\\n`;\n\nconst content = `${fixedHeader}\\\n\\\n${bioContent}\\\n`;\n\nconst binaryData = Buffer.from(content, 'utf8').toString('base64');\n\nreturn [{\n  json: {\n    readme_id: readmeId,\n    content_preview: content\n  },\n  binary: {\n    data: {\n      data: binaryData,\n      mimeType: 'text/markdown',\n      fileName: 'README.md'\n    }\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        5200,
        3072
      ],
      "id": "9dcf7110-cd06-4ae1-9568-703b251d99f9",
      "name": "Prep README Upload"
    },
    {
      "parameters": {
        "operation": "update",
        "fileId": {
          "__rl": true,
          "value": "={{ $json.readme_id }}",
          "mode": "id"
        },
        "changeFileContent": true,
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        5424,
        3072
      ],
      "id": "042ad776-130a-4fb6-a268-fcf56e8a8bf1",
      "name": "Upload Updated README",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "status",
              "name": "status",
              "value": "success",
              "type": "string"
            },
            {
              "id": "email-file-id",
              "name": "email_file_id",
              "value": "={{ $('Upload Email File').first().json.id }}",
              "type": "string"
            },
            {
              "id": "email-file-name",
              "name": "email_file_name",
              "value": "={{ $('Prepare Email File').first().json.filename }}",
              "type": "string"
            },
            {
              "id": "readme-updated",
              "name": "readme_updated",
              "value": true,
              "type": "boolean"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        5648,
        3072
      ],
      "id": "4f81ee7b-fc3c-42bd-9416-12d1aaa5272f",
      "name": "Return Output"
    }
  ],
  "connections": {
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "Prepare Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Prepare Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Input": {
      "main": [
        [
          {
            "node": "Prepare Email File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Email File": {
      "main": [
        [
          {
            "node": "Upload Email File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Email File": {
      "main": [
        [
          {
            "node": "Find README",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find README": {
      "main": [
        [
          {
            "node": "Download README",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download README": {
      "main": [
        [
          {
            "node": "Prep LLM Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prep LLM Input": {
      "main": [
        [
          {
            "node": "LLM: Update Profile",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Profile LLM": {
      "ai_languageModel": [
        [
          {
            "node": "LLM: Update Profile",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "LLM: Update Profile": {
      "main": [
        [
          {
            "node": "Prep README Upload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prep README Upload": {
      "main": [
        [
          {
            "node": "Upload Updated README",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Updated README": {
      "main": [
        [
          {
            "node": "Return Output",
            "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

Contact-Memory-Update. Uses executeWorkflowTrigger, googleDrive, lmChatGroq, chainLlm. Event-driven trigger; 14 nodes.

Source: https://github.com/runfish5/micro-services/blob/main/projects/n8n/02_smart-table-fill/workflows/subworkflows/contact-memory-update.json — original creator credit. Request a take-down →

More General workflows → · Browse all categories →

Related workflows

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

General

Narrating Over A Video Using Multimodal Ai. Uses lmChatOpenAi, splitOut, httpRequest, convertToFile. Event-driven trigger; 21 nodes.

OpenAI Chat, HTTP Request, Google Drive +3
General

Googledrivetool Extractfromfile. Uses stickyNote, executeWorkflowTrigger, mcpTrigger, googleDrive. Event-driven trigger; 17 nodes.

Execute Workflow Trigger, Mcp Trigger, Google Drive +3
General

ESG analysts, investors, procurement teams, activists and sustainability professionals who need comprehensive, objective assessments of companies' environmental impact and animal welfare policies. Per

OpenRouter Chat, Output Parser Structured, Execute Workflow Trigger +1
General

Cv Resume Pdf Parsing With Multimodal Vision Ai. Uses manualTrigger, stickyNote, outputParserStructured, googleDrive. Event-driven trigger; 13 nodes.

Output Parser Structured, Google Drive, HTTP Request +3
General

Stickynote Executeworkflow. Uses executeWorkflowTrigger, chainLlm, outputParserStructured, lmChatOpenRouter. Event-driven trigger; 12 nodes.

Execute Workflow Trigger, Chain Llm, Output Parser Structured +1