{
 "name": "ESSENTIEL-CGP — brouillons de réponse",
 "nodes": [
  {
   "parameters": {},
   "id": "t",
   "name": "Lancer manuellement",
   "type": "n8n-nodes-base.manualTrigger",
   "typeVersion": 1,
   "position": [
    -260,
    300
   ]
  },
  {
   "parameters": {
    "url": "https://gmail.googleapis.com/gmail/v1/users/me/drafts",
    "authentication": "predefinedCredentialType",
    "nodeCredentialType": "gmailOAuth2",
    "sendQuery": true,
    "specifyQuery": "keypair",
    "queryParameters": {
     "parameters": [
      {
       "name": "q",
       "value": "subject:\"[FINAL] Re: Votre profil m'intéresse\""
      },
      {
       "name": "maxResults",
       "value": "1"
      }
     ]
    },
    "options": {}
   },
   "id": "dl",
   "name": "Trouver le brouillon [FINAL]",
   "type": "n8n-nodes-base.httpRequest",
   "typeVersion": 4.2,
   "position": [
    -40,
    180
   ],
   "retryOnFail": true,
   "maxTries": 3
  },
  {
   "parameters": {
    "url": "=https://gmail.googleapis.com/gmail/v1/users/me/drafts/{{ $json.drafts[0].id }}",
    "authentication": "predefinedCredentialType",
    "nodeCredentialType": "gmailOAuth2",
    "sendQuery": true,
    "specifyQuery": "keypair",
    "queryParameters": {
     "parameters": [
      {
       "name": "format",
       "value": "full"
      }
     ]
    },
    "options": {}
   },
   "id": "dg",
   "name": "Charger le gabarit",
   "type": "n8n-nodes-base.httpRequest",
   "typeVersion": 4.2,
   "position": [
    180,
    180
   ],
   "retryOnFail": true,
   "maxTries": 3
  },
  {
   "parameters": {
    "jsCode": "\n// Extrait le HTML + texte du brouillon [FINAL] validé par Fabien.\n// Ce brouillon sert de gabarit : \"Bonjour [Prénom],\" est le marqueur à substituer.\nconst d = $input.first().json;\n\nfunction walk(part, acc) {\n  if (!part) return acc;\n  if (part.mimeType === 'text/html' && part.body && part.body.data) acc.html = part.body.data;\n  if (part.mimeType === 'text/plain' && part.body && part.body.data) acc.text = part.body.data;\n  for (const p of part.parts || []) walk(p, acc);\n  return acc;\n}\nconst acc = walk(d.message && d.message.payload, {});\nfunction dec(b64) {\n  if (!b64) return '';\n  return Buffer.from(b64.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf8');\n}\nconst html = dec(acc.html);\nconst text = dec(acc.text);\n\nif (!html) throw new Error('Brouillon [FINAL] introuvable ou sans partie HTML.');\nif (html.indexOf('[Prénom]') === -1) throw new Error('Marqueur [Prénom] absent du gabarit HTML.');\n\nreturn [{ json: { tplHtml: html, tplText: text } }];\n"
   },
   "id": "ex",
   "name": "Extraire le gabarit",
   "type": "n8n-nodes-base.code",
   "typeVersion": 2,
   "position": [
    400,
    180
   ]
  },
  {
   "parameters": {
    "resource": "message",
    "operation": "getAll",
    "returnAll": true,
    "simple": false,
    "filters": {
     "q": "in:sent subject:\"Votre profil m'intéresse\" after:2026/07/16 before:2026/07/19 -to:fabien@fabien-massavie.com"
    },
    "options": {}
   },
   "id": "gs",
   "name": "Gmail - fils envoyes",
   "type": "n8n-nodes-base.gmail",
   "typeVersion": 2.1,
   "position": [
    400,
    400
   ],
   "retryOnFail": true,
   "maxTries": 3
  },
  {
   "parameters": {
    "jsCode": "const tpl = $('Extraire le gabarit').first().json;\n\nconst EXCLUS = new Set(['olivier@limmedia.fr', 'villemonte@odlcpatrimoine.fr']);\nconst DEJA_FAIT = new Set([\n  'sylvain@groizier.net', 'mmosbahi@gmail.com',\n  'mikael.gueviguian@livingstone-wealth.com', 'yamin.benhenia@gmail.com'\n]);\n\nconst b64 = s => Buffer.from(s, 'utf8').toString('base64');\nconst b64url = s => b64(s).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\nconst hdr = s => '=?UTF-8?B?' + b64(s) + '?=';\n\nconst out = [], ignores = [], vus = new Set();\n\nfor (const it of $('Gmail - fils envoyes').all()) {\n  const m = it.json;\n  // ⚠️ Le noeud Gmail renvoie les en-tetes en OBJET PLAT, pas en tableau payload.headers[]\n  const H = {};\n  const raw = m.headers || {};\n  for (const k of Object.keys(raw)) H[k.toLowerCase()] = String(raw[k] || '');\n\n  const mt = (H['to'] || '').match(/[\\w.+-]+@[\\w.-]+\\.\\w+/);\n  if (!mt) { ignores.push({ r: 'destinataire illisible', id: m.id }); continue; }\n  const to = mt[0].toLowerCase();\n  if (EXCLUS.has(to))    { ignores.push({ r: 'exclu', to }); continue; }\n  if (DEJA_FAIT.has(to)) { ignores.push({ r: 'deja fait', to }); continue; }\n  if (vus.has(to))       { ignores.push({ r: 'doublon', to }); continue; }\n  vus.add(to);\n\n  // Le corps est dans text/html, pas dans snippet\n  const corps = (m.text || '') + ' ' + (m.html || '');\n  const mp = corps.match(/Bonjour\\s+([A-Za-zÀ-ÿ'\\-]+(?:\\s[A-Za-zÀ-ÿ'\\-]+)?)\\s*,/);\n  if (!mp) { ignores.push({ r: 'prenom introuvable', to }); continue; }\n  const prenom = mp[1].trim();\n\n  const html = tpl.tplHtml.split('[Prénom]').join(prenom);\n  const text = (tpl.tplText || '').split('[Prénom]').join(prenom);\n\n  // Le sujet d'origine est MIME-encode : on reconstruit en dur\n  const midm = (H['message-id'] || '').match(/<[^>]+>/);\n  const mid = midm ? midm[0] : '';\n\n  const b = '----=_P_' + Math.random().toString(36).slice(2, 12);\n  const L = ['To: ' + to, 'Subject: ' + hdr(\"Re: Votre profil m'intéresse\")];\n  if (mid) { L.push('In-Reply-To: ' + mid, 'References: ' + mid); }\n  L.push('MIME-Version: 1.0', 'Content-Type: multipart/alternative; boundary=\"' + b + '\"', '',\n    '--' + b, 'Content-Type: text/plain; charset=\"UTF-8\"', 'Content-Transfer-Encoding: base64', '', b64(text),\n    '--' + b, 'Content-Type: text/html; charset=\"UTF-8\"', 'Content-Transfer-Encoding: base64', '', b64(html),\n    '--' + b + '--', '');\n\n  out.push({ json: { threadId: m.threadId, to, prenom, raw: b64url(L.join('\\r\\n')) } });\n}\n\nconsole.log('A creer: ' + out.length + ' | Ignores: ' + ignores.length);\nconsole.log(JSON.stringify(ignores.slice(0, 40), null, 2));\nif (!out.length) throw new Error('Aucun brouillon a creer.');\nreturn out;"
   },
   "id": "bd",
   "name": "Construire les brouillons",
   "type": "n8n-nodes-base.code",
   "typeVersion": 2,
   "position": [
    640,
    300
   ]
  },
  {
   "parameters": {
    "method": "POST",
    "url": "https://gmail.googleapis.com/gmail/v1/users/me/drafts",
    "authentication": "predefinedCredentialType",
    "nodeCredentialType": "gmailOAuth2",
    "sendBody": true,
    "specifyBody": "json",
    "jsonBody": "={{ JSON.stringify({ message: { raw: $json.raw, threadId: $json.threadId } }) }}",
    "options": {
     "batching": {
      "batch": {
       "batchSize": 5,
       "batchInterval": 1200
      }
     },
     "timeout": 20000
    }
   },
   "id": "cr",
   "name": "Creer le brouillon (DRAFT)",
   "type": "n8n-nodes-base.httpRequest",
   "typeVersion": 4.2,
   "position": [
    880,
    300
   ],
   "retryOnFail": true,
   "maxTries": 3,
   "waitBetweenTries": 3000,
   "onError": "continueRegularOutput"
  },
  {
   "parameters": {
    "content": "## N'ENVOIE RIEN\n\nAppelle `drafts.create`, jamais `messages.send`.\nChaque brouillon se place dans le fil d'origine (threadId + In-Reply-To + References).\n\n## Gabarit\nLe HTML n'est pas stocke ici : il est lu depuis le brouillon Gmail **[FINAL] Re: Votre profil m'interesse**, valide par Fabien. Le marqueur `[Prénom]` y est substitue.\n\n**Edition n°2** : creer un nouveau brouillon `[FINAL] ...`, vider DEJA_FAIT, ajuster les dates.\n\n## Exclusions\n- olivier@limmedia.fr (pas CGP)\n- villemonte@odlcpatrimoine.fr (bounce)",
    "height": 420,
    "width": 420,
    "color": 3
   },
   "id": "sn",
   "name": "Note",
   "type": "n8n-nodes-base.stickyNote",
   "typeVersion": 1,
   "position": [
    -280,
    -120
   ]
  }
 ],
 "connections": {
  "Lancer manuellement": {
   "main": [
    [
     {
      "node": "Trouver le brouillon [FINAL]",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Trouver le brouillon [FINAL]": {
   "main": [
    [
     {
      "node": "Charger le gabarit",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Charger le gabarit": {
   "main": [
    [
     {
      "node": "Extraire le gabarit",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Extraire le gabarit": {
   "main": [
    [
     {
      "node": "Gmail - fils envoyes",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Gmail - fils envoyes": {
   "main": [
    [
     {
      "node": "Construire les brouillons",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Construire les brouillons": {
   "main": [
    [
     {
      "node": "Creer le brouillon (DRAFT)",
      "type": "main",
      "index": 0
     }
    ]
   ]
  }
 },
 "settings": {
  "executionOrder": "v1",
  "timezone": "Europe/Paris"
 },
 "pinData": {},
 "meta": {
  "derniereExecution": "2026-07-18T21:07:29Z",
  "brouillonsCrees": 130
 }
}