{
  "id": "UR98jinnwjEocwVT",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Email Contacts Sync from Sent Mailbox to Odoo",
  "tags": [
    {
      "id": "6ZEKwNveBvfSidIt",
      "name": "Gmail",
      "createdAt": "2025-04-02T07:57:20.398Z",
      "updatedAt": "2025-04-02T07:57:20.398Z"
    },
    {
      "id": "HyLSX6V7QZs5MrZy",
      "name": "Odoo",
      "createdAt": "2025-03-24T01:54:27.030Z",
      "updatedAt": "2025-03-24T01:54:27.030Z"
    }
  ],
  "nodes": [
    {
      "id": "9ba53878-ef58-4926-b5a7-1f7e6a11db53",
      "name": "End",
      "type": "n8n-nodes-base.noOp",
      "position": [
        384,
        1008
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "69e88df5-3338-46c2-845b-7778a54502a8",
      "name": "Step 1: Schedule Trigger every day at 7 AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -768,
        912
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": "={{ 07 }}",
              "triggerAtMinute": "={{ 0 }}"
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "8b34fc77-07b8-4cfc-aa86-94de5d323cd1",
      "name": "Step 2: Set Variables",
      "type": "n8n-nodes-base.set",
      "position": [
        -544,
        912
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "={\n  \"limit\": 100,\n  \"days_ago\": 10,\n  \"mailing_contact_web_search_read\": \"end_point\",\n  \"mailing_contact_web_save\": \"end_point\",\n  \"020_Good_to_send\": 991,\n  \"mail_blacklist_web_search_read\": \"end_point\",\n  \"mail_blacklist_web_save\": \"end_point\"\n}"
      },
      "executeOnce": true,
      "typeVersion": 3.4
    },
    {
      "id": "d57d0cc8-75ed-4cba-992d-da9d8e2bd0e1",
      "name": "Step 3: Get date time",
      "type": "n8n-nodes-base.code",
      "position": [
        -336,
        912
      ],
      "parameters": {
        "jsCode": "const today = new Date();\n\ntoday.setDate(today.getDate() - $input.first().json.days_ago);\n\nconst yyyy = today.getFullYear();\nconst mm = String(today.getMonth() + 1).padStart(2, '0');\nconst dd = String(today.getDate()).padStart(2, '0');\n\nconst after = `${yyyy}/${mm}/${dd}`;\n \nconst next = new Date(today);\nnext.setDate(next.getDate() + 1);\n\nconst afterNext = `${next.getFullYear()}/${String(next.getMonth()+1).padStart(2,'0')}/${String(next.getDate()).padStart(2,'0')}`;\n\nreturn {\n  after,\n  before: afterNext\n};\n"
      },
      "typeVersion": 2
    },
    {
      "id": "778eef83-d3d9-48aa-bfd3-b5c6a9e8cc38",
      "name": "Step 4:Get the list of emails sent 10 days ago.",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -96,
        912
      ],
      "parameters": {
        "url": "https://gmail.googleapis.com/gmail/v1/users/me/messages",
        "options": {},
        "sendQuery": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "=q",
              "value": "=in:sent after:{{$json.after}} before:{{$json.before}}"
            },
            {
              "name": "=maxResults",
              "value": "=1000"
            }
          ]
        },
        "nodeCredentialType": "gmailOAuth2"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        },
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": true
    },
    {
      "id": "129e5bc6-5a4d-47b2-9bc4-4b6af38b2a7e",
      "name": "Step 5: If resultSizeEstimate has a record ==> true",
      "type": "n8n-nodes-base.if",
      "position": [
        144,
        912
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "67886917-88be-4839-b1fb-35735310336b",
              "operator": {
                "type": "number",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.resultSizeEstimate }}",
              "rightValue": "={{ 0 }}"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "a919bc3d-a946-4a1d-b033-cceee803e231",
      "name": "Step 6: Split Out emails sent",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        384,
        800
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "messages"
      },
      "executeOnce": true,
      "retryOnFail": true,
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "5ada64a1-c4b7-4a14-8a1b-0c38f55c9e8b",
      "name": "Step 7: Loop Over email sent",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        640,
        800
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "e28369de-1c64-4e49-a7c4-0b1ec469aa9f",
      "name": "Step 8: Get email information about thread_id",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        864,
        960
      ],
      "parameters": {
        "url": "=https://gmail.googleapis.com/gmail/v1/users/me/threads/{{ $json.threadId }}",
        "options": {},
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "gmailOAuth2"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        },
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.2,
      "alwaysOutputData": true
    },
    {
      "id": "ba367a78-e5ad-4a35-8ad9-574360e06bc2",
      "name": "Step 9: Handling mail sorting from headers",
      "type": "n8n-nodes-base.code",
      "position": [
        640,
        960
      ],
      "parameters": {
        "jsCode": "const messages = $node[\"Step 8: Get email information about thread_id\"].json.messages || [];\nconst getHeader = (headers, name) =>\n  headers.find(h => h.name === name)?.value || null;\n\nfunction parseRecipients(value) {\n  if (!value) return [];\n\n  return value\n    .split(',')\n    .map(r => {\n      const trimmed = r.trim();\n      const match = trimmed.match(/^(.*?)\\s*<([^>]+)>$/);\n\n      if (match) {\n        return {\n          name: match[1].replace(/\"/g, '').trim(),\n          email: match[2].toLowerCase().trim()\n        };\n      }\n\n      return {\n        name: trimmed.split('@')[0],\n        email: trimmed.toLowerCase()\n      };\n    })\n    .filter(r => r.email);\n}\n\nconst unique = (arr) =>\n  [...new Map(arr.map(r => [r.email, r])).values()];\n\nlet originalRecipients = [];\n\nfor (const msg of messages) {\n  const headers = msg.payload?.headers || [];\n\n  const inReply = getHeader(headers, \"In-Reply-To\");\n\n  // The first message does NOT have an In-Reply-To\n  if (!inReply) {\n    const toList = parseRecipients(getHeader(headers, \"To\"));\n    originalRecipients.push(...toList);\n  }\n}\n\noriginalRecipients = unique(originalRecipients);\n\nlet replied = [];\nlet bounced = [];\nlet autoReply = [];\n\nfor (const msg of messages) {\n  const headers = msg.payload?.headers || [];\n\n  const from = parseRecipients(getHeader(headers, \"From\"))[0];\n  if (!from) continue;\n\n  const subject = (getHeader(headers, \"Subject\") || \"\").toLowerCase();\n  const inReply = getHeader(headers, \"In-Reply-To\");\n  const autoSub = getHeader(headers, \"Auto-Submitted\");\n\n  const fromEmail = from.email;\n\n  /******** BOUNCE ********/\n  const isBounce =\n    fromEmail.includes(\"mailer-daemon\") ||\n    subject.includes(\"delivery status notification\") ||\n    subject.includes(\"failure notice\");\n\n  if (isBounce) {\n    bounced.push(...originalRecipients);\n    continue;\n  }\n\n  /******** AUTO ********/\n  if (autoSub) {\n    autoReply.push(from);\n    continue;\n  }\n\n  /******** REAL REPLY ********/\n  if (inReply) {\n    replied.push(from);\n  }\n}\n\nreplied = unique(replied);\nbounced = unique(bounced);\nautoReply = unique(autoReply);\n\nconst repliedSet = new Set(replied.map(r => r.email));\nconst bouncedSet = new Set(bounced.map(r => r.email));\n\nconst deliver = originalRecipients.filter(\n  r => !bouncedSet.has(r.email)\n);\n\nconst noResponse = deliver.filter(\n  r => !repliedSet.has(r.email)\n);\n\nreturn {\n  deliverableEmails: deliver,\n  repliedEmails: replied,\n  bounceEmails: bounced,\n  autoReplies: autoReply,\n  noResponse\n};\n"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "c653a801-7bf6-4142-8c0c-a3aad0737931",
      "name": "Step 10: Merge the categorized mailing lists",
      "type": "n8n-nodes-base.code",
      "position": [
        864,
        784
      ],
      "parameters": {
        "jsCode": "const items = $input.all().map(i => i.json);\n\nlet deliver = [];\nlet replied = [];\nlet bounce = [];\nlet autoReply = [];\nlet noResponse = [];\n\nfor (const data of items) {\n  deliver.push(...(data.deliverableEmails || []));\n  replied.push(...(data.repliedEmails || []));\n  bounce.push(...(data.bounceEmails || []));\n  autoReply.push(...(data.autoReplies || []));\n  noResponse.push(...(data.noResponse || []));\n}\n\nconst unique = (arr) =>\n  [...new Map(arr.map(x => [x.email, x])).values()];\n\ndeliver = unique(deliver);\nreplied = unique(replied);\nbounce = unique(bounce);\nautoReply = unique(autoReply);\nnoResponse = unique(noResponse);\n\nreturn [\n  {\n    json: {\n      deliverableEmails: deliver,\n      repliedEmails: replied,\n      bounceEmails: bounce,\n      autoReplies: autoReply,\n      noResponse: noResponse\n    }\n  }\n];\n"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "4283c715-1651-4a49-a563-7b9db0b755d6",
      "name": "Step 14: Search email in Mailing List Contacts",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1584,
        704
      ],
      "parameters": {
        "url": "={{ $node['Step 2: Set Variables'].json.mailing_contact_web_search_read }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"id\": 8,\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"call\",\n  \"params\": {\n    \"model\": \"mailing.contact\",\n    \"method\": \"web_search_read\",\n    \"args\": [],\n    \"kwargs\": {\n      \"specification\": {\n        \"id_contact_hubspot\": {},\n        \"create_date\": {},\n        \"title_id\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"name\": {},\n        \"company_name\": {},\n        \"email\": {},\n        \"is_blacklisted\": {},\n        \"country_id\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"position_extra\": {},\n        \"state_name\": {},\n        \"industry_name\": {},\n        \"linkedIn_URL\": {},\n        \"numberofemployees\": {},\n        \"is_fix_list\": {},\n        \"message_bounce\": {},\n        \"opt_out\": {},\n        \"list_ids\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        }\n      },\n      \"offset\": 0,\n      \"order\": \"\",\n      \"limit\": 80,\n      \"context\": {\n        \"lang\": \"en_US\",\n        \"tz\": \"Asia/Saigon\",\n        \"allowed_company_ids\": [\n          1\n        ],\n        \"bin_size\": true,\n        \"params\": {\n          \"action\": 763,\n          \"actionStack\": [\n            {\n              \"action\": 763\n            }\n          ]\n        },\n        \"update_mailing_type\": \"manual\",\n        \"current_company_id\": 1\n      },\n      \"count_limit\": 10001,\n      \"domain\": [\n        \"&\",\n        [\n          \"is_blacklisted\",\n          \"=\",\n          false\n        ],\n        \"|\",\n        \"|\",\n        [\n          \"name\",\n          \"ilike\",\n          \"{{ $json.email }}\"\n        ],\n        [\n          \"company_name\",\n          \"ilike\",\n          \"{{ $json.email }}\"\n        ],\n        [\n          \"email_normalized\",\n          \"ilike\",\n          \"{{ $json.email }}\"\n        ]\n      ]\n    }\n  }\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "retryOnFail": true,
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "ff6a0581-0c15-4615-b100-d0296f9c9ae3",
      "name": "Step 15: If number of records is not 0 = true",
      "type": "n8n-nodes-base.if",
      "position": [
        1776,
        704
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cc1372a4-cc7d-4ace-9a73-0055e6920e0c",
              "operator": {
                "type": "number",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.result.length }}",
              "rightValue": "={{ 0 }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "6eb6ef12-0a42-40aa-82e6-983f2d05fee8",
      "name": "Step 16.1\" Check if list_ids contains 020.Good-to-send",
      "type": "n8n-nodes-base.code",
      "position": [
        1984,
        608
      ],
      "parameters": {
        "jsCode": "const inputData = $input.all();\nconst list_ids = inputData[0]?.json?.result?.records[0]?.list_ids || [];\nconst id = inputData[0]?.json?.result?.records[0]?.id;\nlet islist_ids = false;\n\nif (list_ids.length > 0) {\n    islist_ids = list_ids.some(item => item.id === $node['Step 2: Set Variables'].json.020_Good_to_send);\n}\n\nreturn { islist_ids, id };\n"
      },
      "typeVersion": 2
    },
    {
      "id": "07637692-9598-4a2c-90e4-7cb47d874e66",
      "name": "Step 16.2: Add new email in Mailing List Contacts",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1984,
        800
      ],
      "parameters": {
        "url": "={{ $node['Step 2: Set Variables'].json.mailing_contact_web_save }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"id\": 18,\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"call\",\n  \"params\": {\n    \"model\": \"mailing.contact\",\n    \"method\": \"web_save\",\n    \"args\": [\n      [],\n      {\n        \"name\": \"\",\n        \"first_name\": \"\",\n        \"last_name\": \"\",\n        \"position_extra\": false,\n        \"email\": \"{{ $('Step 13: Loop Over deliverableEmails').item.json.email }}\",\n        \"title_id\": false,\n        \"company_name\": false,\n        \"country_id\": false,\n        \"state_name\": false,\n        \"industry_name\": false,\n        \"numberofemployees\": false,\n        \"company_related\": false,\n        \"linkedIn_URL\": false,\n        \"tag_ids\": [],\n        \"subscription_ids\": [\n          [\n            0,\n            \"virtual_249\",\n            {\n              \"list_id\": {{ $node['Step 2: Set Variables'].json['020_Good_to_send'] }},\n              \"opt_out\": false,\n              \"opt_out_reason_id\": false\n            }\n          ]\n        ]\n      }\n    ],\n    \"kwargs\": {\n      \"context\": {\n        \"lang\": \"en_US\",\n        \"tz\": \"Asia/Saigon\",\n        \"allowed_company_ids\": [\n          1\n        ],\n        \"params\": {\n          \"action\": 763,\n          \"actionStack\": [\n            {\n              \"action\": 763\n            }\n          ]\n        },\n        \"update_mailing_type\": \"manual\"\n      },\n      \"specification\": {\n        \"id\": {},\n        \"name\": {},\n        \"first_name\": {},\n        \"last_name\": {},\n        \"position_extra\": {},\n        \"email\": {},\n        \"is_blacklisted\": {},\n        \"title_id\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"company_name\": {},\n        \"country_id\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"state_name\": {},\n        \"create_date\": {},\n        \"message_bounce\": {},\n        \"industry_name\": {},\n        \"numberofemployees\": {},\n        \"company_related\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"linkedIn_URL\": {},\n        \"tag_ids\": {\n          \"fields\": {\n            \"display_name\": {},\n            \"color\": {}\n          }\n        },\n        \"subscription_ids\": {\n          \"fields\": {\n            \"id\": {},\n            \"list_id\": {\n              \"fields\": {\n                \"display_name\": {}\n              }\n            },\n            \"opt_out_datetime\": {},\n            \"opt_out\": {},\n            \"opt_out_reason_id\": {\n              \"fields\": {\n                \"display_name\": {}\n              }\n            },\n            \"create_date\": {}\n          },\n          \"limit\": 100,\n          \"order\": \"\"\n        },\n        \"display_name\": {}\n      }\n    }\n  }\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "retryOnFail": true,
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "5c23917e-e814-4c11-ac3c-cbc155a7af82",
      "name": "Step 17: If list_ids = true",
      "type": "n8n-nodes-base.if",
      "position": [
        2192,
        704
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5995af10-bfe3-4ea0-ac6a-6e218bfa36da",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.islist_ids }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "c0df8b49-2354-4ef0-8985-451d56b733af",
      "name": "Step 18: Update email in Mailing List Contacts",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2400,
        704
      ],
      "parameters": {
        "url": "={{ $node['Step 2: Set Variables'].json.mailing_contact_web_save }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"id\": 11,\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"call\",\n  \"params\": {\n    \"model\": \"mailing.contact\",\n    \"method\": \"web_save\",\n    \"args\": [\n      [\n        {{ $node['Step 17: If list_ids = true'].json.id }}\n      ],\n      {\n        \"subscription_ids\": [\n          [\n            0,\n            \"virtual_7\",\n            {\n              \"list_id\": {{ $node['Step 2: Set Variables'].json['020_Good_to_send'] }},\n              \"opt_out\": false,\n              \"opt_out_reason_id\": false\n            }\n          ]\n        ]\n      }\n    ],\n    \"kwargs\": {\n      \"context\": {\n        \"lang\": \"en_US\",\n        \"tz\": \"Asia/Saigon\",\n        \"allowed_company_ids\": [\n          1\n        ],\n        \"params\": {\n          \"resId\": {{ $node['Step 17: If list_ids = true'].json.id }},\n          \"action\": 763,\n          \"actionStack\": [\n            {\n              \"action\": 763\n            },\n            {\n              \"resId\": {{ $node['Step 17: If list_ids = true'].json.id }},\n              \"action\": 763\n            }\n          ]\n        },\n        \"update_mailing_type\": \"manual\"\n      },\n      \"specification\": {\n        \"id\": {},\n        \"name\": {},\n        \"first_name\": {},\n        \"last_name\": {},\n        \"position_extra\": {},\n        \"email\": {},\n        \"is_blacklisted\": {},\n        \"title_id\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"company_name\": {},\n        \"country_id\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"state_name\": {},\n        \"create_date\": {},\n        \"message_bounce\": {},\n        \"industry_name\": {},\n        \"numberofemployees\": {},\n        \"company_related\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"linkedIn_URL\": {},\n        \"tag_ids\": {\n          \"fields\": {\n            \"display_name\": {},\n            \"color\": {}\n          }\n        },\n        \"subscription_ids\": {\n          \"fields\": {\n            \"id\": {},\n            \"list_id\": {\n              \"fields\": {\n                \"display_name\": {}\n              }\n            },\n            \"opt_out_datetime\": {},\n            \"opt_out\": {},\n            \"opt_out_reason_id\": {\n              \"fields\": {\n                \"display_name\": {}\n              }\n            },\n            \"create_date\": {}\n          },\n          \"limit\": 100,\n          \"order\": \"\"\n        },\n        \"display_name\": {}\n      }\n    }\n  }\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "retryOnFail": true,
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "50510a57-bdbb-46de-91cc-ab11833e9fec",
      "name": "Step 19: Return all data from step 10.",
      "type": "n8n-nodes-base.code",
      "position": [
        2624,
        496
      ],
      "parameters": {
        "jsCode": "const data = $items(\"Step 10: Merge the categorized mailing lists\");\nreturn data"
      },
      "executeOnce": true,
      "typeVersion": 2
    },
    {
      "id": "5c7f9750-b12a-46ca-90be-592ed3b606c1",
      "name": "Step 20: Split Out bounceEmails",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        2816,
        496
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "bounceEmails"
      },
      "retryOnFail": true,
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "2819cfa6-6a12-4890-9f5b-57f8865055ca",
      "name": "Step 21: Loop Over bounceEmails",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        3024,
        496
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "1106af9f-ecd3-4cd8-9c69-2421b61c2258",
      "name": "Step 22: Search email in Blacklisted Email Addresses",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3024,
        688
      ],
      "parameters": {
        "url": "={{ $node['Step 2: Set Variables'].json.mail_blacklist_web_search_read }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"id\": 47,\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"call\",\n  \"params\": {\n    \"model\": \"mail.blacklist\",\n    \"method\": \"web_search_read\",\n    \"args\": [],\n    \"kwargs\": {\n      \"specification\": {\n        \"create_date\": {},\n        \"email\": {},\n        \"reason_type\": {},\n        \"id_contact_hubspot\": {},\n        \"opt_out_reason_id\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"create_uid\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"write_uid\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        }\n      },\n      \"offset\": 0,\n      \"order\": \"\",\n      \"limit\": 100,\n      \"context\": {\n        \"lang\": \"en_US\",\n        \"tz\": \"Asia/Bangkok\",\n        \"allowed_company_ids\": [\n          1\n        ],\n        \"bin_size\": true,\n        \"current_company_id\": 1\n      },\n      \"count_limit\": 10001,\n      \"domain\": [\n        [\n          \"email\",\n          \"ilike\",\n          \"{{ $json.email }}\"\n        ]\n      ]\n    }\n  }\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "retryOnFail": true,
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "d9b26770-e5a6-49f1-bb74-1f1e399837e3",
      "name": "Step 23: If number of records is not 0 = true",
      "type": "n8n-nodes-base.if",
      "position": [
        3232,
        688
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cc1372a4-cc7d-4ace-9a73-0055e6920e0c",
              "operator": {
                "type": "number",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.result.length }}",
              "rightValue": "={{ 0 }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "f57626ff-2ced-42bc-8e16-0b845371fe1b",
      "name": "Step 24.1\" Check if reason_type contains Bounced",
      "type": "n8n-nodes-base.code",
      "position": [
        3440,
        592
      ],
      "parameters": {
        "jsCode": "const record = $input.all()?.[0]?.json?.result?.records?.[0] ?? {};\n\nreturn {\n  id: record.id,\n  isBounced: (record.reason_type || \"\").toLowerCase() === \"bounced\"\n};\n"
      },
      "typeVersion": 2
    },
    {
      "id": "391adb70-caf3-4bc2-bb00-db5032c98ec5",
      "name": "Step 24.2: Add new email in Blacklisted Email Addresses",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3440,
        784
      ],
      "parameters": {
        "url": "={{ $node['Step 2: Set Variables'].json.mail_blacklist_web_save }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"id\": 65,\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"call\",\n  \"params\": {\n    \"model\": \"mail.blacklist\",\n    \"method\": \"web_save\",\n    \"args\": [\n      [],\n      {\n        \"email\": \"{{ $('Step 21: Loop Over bounceEmails').item.json.email }}\",\n        \"id_contact_hubspot\": false,\n        \"reason_type\": \"bounced\",\n        \"opt_out_reason_id\": false\n      }\n    ],\n    \"kwargs\": {\n      \"context\": {\n        \"lang\": \"en_US\",\n        \"tz\": \"Asia/Bangkok\",\n        \"allowed_company_ids\": [\n          1\n        ],\n        \"params\": {\n          \"actionStack\": [\n            {\n              \"displayName\": \"Blacklisted Email Addresses\",\n              \"action\": 147,\n              \"view_type\": \"list\"\n            }\n          ],\n          \"action\": 147,\n          \"globalState\": {\n            \"searchModel\": \"{\\\"nextGroupId\\\":4,\\\"nextGroupNumber\\\":5,\\\"nextId\\\":4,\\\"query\\\":[],\\\"searchItems\\\":{\\\"1\\\":{\\\"type\\\":\\\"field\\\",\\\"fieldName\\\":\\\"email\\\",\\\"fieldType\\\":\\\"char\\\",\\\"description\\\":\\\"Email Address\\\",\\\"groupId\\\":1,\\\"id\\\":1},\\\"2\\\":{\\\"type\\\":\\\"filter\\\",\\\"domain\\\":\\\"[('active','=',False)]\\\",\\\"groupNumber\\\":2,\\\"name\\\":\\\"inactive\\\",\\\"description\\\":\\\"Archived\\\",\\\"groupId\\\":2,\\\"id\\\":2},\\\"3\\\":{\\\"type\\\":\\\"groupBy\\\",\\\"fieldName\\\":\\\"opt_out_reason_id\\\",\\\"fieldType\\\":\\\"many2one\\\",\\\"groupNumber\\\":4,\\\"name\\\":\\\"group_by_opt_out_reason_id\\\",\\\"description\\\":\\\"Reason\\\",\\\"groupId\\\":3,\\\"id\\\":3}},\\\"searchPanelInfo\\\":{\\\"className\\\":\\\"\\\",\\\"fold\\\":false,\\\"viewTypes\\\":[\\\"kanban\\\",\\\"list\\\"],\\\"loaded\\\":false,\\\"shouldReload\\\":true},\\\"sections\\\":[]}\"\n          }\n        }\n      },\n      \"specification\": {\n        \"email\": {},\n        \"id_contact_hubspot\": {},\n        \"reason_type\": {},\n        \"opt_out_reason_id\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"active\": {},\n        \"display_name\": {}\n      }\n    }\n  }\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "retryOnFail": true,
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "154d44eb-f19d-4357-9387-8e7904148f10",
      "name": "Step 25: If list_ids = true",
      "type": "n8n-nodes-base.if",
      "position": [
        3648,
        688
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5995af10-bfe3-4ea0-ac6a-6e218bfa36da",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.isBounced }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "a33c682d-5860-47f0-aaf8-3a0c4ca3fe85",
      "name": "Step 26: Update Reason Type of email in Blacklisted Email Addresses",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3856,
        688
      ],
      "parameters": {
        "url": "={{ $node['Step 2: Set Variables'].json.mail_blacklist_web_save }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"id\": 71,\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"call\",\n  \"params\": {\n    \"model\": \"mail.blacklist\",\n    \"method\": \"web_save\",\n    \"args\": [\n      [\n        {{ $node['Step 25: If list_ids = true'].json.id }}\n      ],\n      {\n        \"reason_type\": \"bounced\"\n      }\n    ],\n    \"kwargs\": {\n      \"context\": {\n        \"lang\": \"en_US\",\n        \"tz\": \"Asia/Bangkok\",\n        \"allowed_company_ids\": [\n          1\n        ],\n        \"params\": {\n          \"actionStack\": [\n            {\n              \"displayName\": \"Blacklisted Email Addresses\",\n              \"action\": 147,\n              \"view_type\": \"list\"\n            }\n          ],\n          \"action\": 147,\n          \"globalState\": {\n            \"searchModel\": \"{\\\"nextGroupId\\\":4,\\\"nextGroupNumber\\\":5,\\\"nextId\\\":4,\\\"query\\\":[],\\\"searchItems\\\":{\\\"1\\\":{\\\"type\\\":\\\"field\\\",\\\"fieldName\\\":\\\"email\\\",\\\"fieldType\\\":\\\"char\\\",\\\"description\\\":\\\"Email Address\\\",\\\"groupId\\\":1,\\\"id\\\":1},\\\"2\\\":{\\\"type\\\":\\\"filter\\\",\\\"domain\\\":\\\"[('active','=',False)]\\\",\\\"groupNumber\\\":2,\\\"name\\\":\\\"inactive\\\",\\\"description\\\":\\\"Archived\\\",\\\"groupId\\\":2,\\\"id\\\":2},\\\"3\\\":{\\\"type\\\":\\\"groupBy\\\",\\\"fieldName\\\":\\\"opt_out_reason_id\\\",\\\"fieldType\\\":\\\"many2one\\\",\\\"groupNumber\\\":4,\\\"name\\\":\\\"group_by_opt_out_reason_id\\\",\\\"description\\\":\\\"Reason\\\",\\\"groupId\\\":3,\\\"id\\\":3}},\\\"searchPanelInfo\\\":{\\\"className\\\":\\\"\\\",\\\"fold\\\":false,\\\"viewTypes\\\":[\\\"kanban\\\",\\\"list\\\"],\\\"loaded\\\":false,\\\"shouldReload\\\":true},\\\"sections\\\":[]}\"\n          }\n        }\n      },\n      \"specification\": {\n        \"email\": {},\n        \"id_contact_hubspot\": {},\n        \"reason_type\": {},\n        \"opt_out_reason_id\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"active\": {},\n        \"display_name\": {}\n      }\n    }\n  }\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "retryOnFail": true,
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "f9675854-47ef-4550-bbe1-67f307212ebf",
      "name": "Step 27: If has record bounceEmails",
      "type": "n8n-nodes-base.if",
      "position": [
        1328,
        1280
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "45a079bb-5e20-4741-9b20-0031799fe2b4",
              "operator": {
                "type": "array",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.bounceEmails }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "423d6ac0-5304-4db4-af1f-df7eaf952e5a",
      "name": "Step 28: Split Out bounceEmails",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1552,
        1184
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "bounceEmails"
      },
      "typeVersion": 1
    },
    {
      "id": "9290cfbb-47af-4ec4-b9c3-b80c4ad75a52",
      "name": "Step 29: Loop Over bounceEmails",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1792,
        1184
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "e6bd0479-de0d-4330-a781-9e7ceec6f2a5",
      "name": "Step 30: Search email in Blacklisted Email Addresses",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1792,
        1376
      ],
      "parameters": {
        "url": "={{ $node['Step 2: Set Variables'].json.mail_blacklist_web_search_read }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"id\": 47,\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"call\",\n  \"params\": {\n    \"model\": \"mail.blacklist\",\n    \"method\": \"web_search_read\",\n    \"args\": [],\n    \"kwargs\": {\n      \"specification\": {\n        \"create_date\": {},\n        \"email\": {},\n        \"reason_type\": {},\n        \"id_contact_hubspot\": {},\n        \"opt_out_reason_id\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"create_uid\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"write_uid\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        }\n      },\n      \"offset\": 0,\n      \"order\": \"\",\n      \"limit\": 100,\n      \"context\": {\n        \"lang\": \"en_US\",\n        \"tz\": \"Asia/Bangkok\",\n        \"allowed_company_ids\": [\n          1\n        ],\n        \"bin_size\": true,\n        \"current_company_id\": 1\n      },\n      \"count_limit\": 10001,\n      \"domain\": [\n        [\n          \"email\",\n          \"ilike\",\n          \"{{ $json.email }}\"\n        ]\n      ]\n    }\n  }\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "retryOnFail": true,
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "8d452689-58a7-4e27-a513-aed4efa5bd3d",
      "name": "Step 31: If number of records is not 0 = true",
      "type": "n8n-nodes-base.if",
      "position": [
        2000,
        1376
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cc1372a4-cc7d-4ace-9a73-0055e6920e0c",
              "operator": {
                "type": "number",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.result.length }}",
              "rightValue": "={{ 0 }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "a5536923-dd58-4dc8-8de2-106b3fc12add",
      "name": "Step 32.1: Check if reason_type contains Bounced",
      "type": "n8n-nodes-base.code",
      "position": [
        2224,
        1280
      ],
      "parameters": {
        "jsCode": "const record = $input.all()?.[0]?.json?.result?.records?.[0] ?? {};\n\nreturn {\n  id: record.id,\n  isBounced: (record.reason_type || \"\").toLowerCase() === \"bounced\"\n};\n"
      },
      "typeVersion": 2
    },
    {
      "id": "f7e15ab6-b89c-40fd-a204-9cd262844774",
      "name": "Step 32.2: Add new email in Blacklisted Email Addresses",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2224,
        1472
      ],
      "parameters": {
        "url": "={{ $node['Step 2: Set Variables'].json.mail_blacklist_web_save }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"id\": 65,\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"call\",\n  \"params\": {\n    \"model\": \"mail.blacklist\",\n    \"method\": \"web_save\",\n    \"args\": [\n      [],\n      {\n        \"email\": \"{{ $('Step 29: Loop Over bounceEmails').item.json.email }}\",\n        \"id_contact_hubspot\": false,\n        \"reason_type\": \"bounced\",\n        \"opt_out_reason_id\": false\n      }\n    ],\n    \"kwargs\": {\n      \"context\": {\n        \"lang\": \"en_US\",\n        \"tz\": \"Asia/Bangkok\",\n        \"allowed_company_ids\": [\n          1\n        ],\n        \"params\": {\n          \"actionStack\": [\n            {\n              \"displayName\": \"Blacklisted Email Addresses\",\n              \"action\": 147,\n              \"view_type\": \"list\"\n            }\n          ],\n          \"action\": 147,\n          \"globalState\": {\n            \"searchModel\": \"{\\\"nextGroupId\\\":4,\\\"nextGroupNumber\\\":5,\\\"nextId\\\":4,\\\"query\\\":[],\\\"searchItems\\\":{\\\"1\\\":{\\\"type\\\":\\\"field\\\",\\\"fieldName\\\":\\\"email\\\",\\\"fieldType\\\":\\\"char\\\",\\\"description\\\":\\\"Email Address\\\",\\\"groupId\\\":1,\\\"id\\\":1},\\\"2\\\":{\\\"type\\\":\\\"filter\\\",\\\"domain\\\":\\\"[('active','=',False)]\\\",\\\"groupNumber\\\":2,\\\"name\\\":\\\"inactive\\\",\\\"description\\\":\\\"Archived\\\",\\\"groupId\\\":2,\\\"id\\\":2},\\\"3\\\":{\\\"type\\\":\\\"groupBy\\\",\\\"fieldName\\\":\\\"opt_out_reason_id\\\",\\\"fieldType\\\":\\\"many2one\\\",\\\"groupNumber\\\":4,\\\"name\\\":\\\"group_by_opt_out_reason_id\\\",\\\"description\\\":\\\"Reason\\\",\\\"groupId\\\":3,\\\"id\\\":3}},\\\"searchPanelInfo\\\":{\\\"className\\\":\\\"\\\",\\\"fold\\\":false,\\\"viewTypes\\\":[\\\"kanban\\\",\\\"list\\\"],\\\"loaded\\\":false,\\\"shouldReload\\\":true},\\\"sections\\\":[]}\"\n          }\n        }\n      },\n      \"specification\": {\n        \"email\": {},\n        \"id_contact_hubspot\": {},\n        \"reason_type\": {},\n        \"opt_out_reason_id\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"active\": {},\n        \"display_name\": {}\n      }\n    }\n  }\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "retryOnFail": true,
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "cd6e113f-9f2b-44d3-966a-b7158eefd37f",
      "name": "Step 33: If list_ids = true",
      "type": "n8n-nodes-base.if",
      "position": [
        2448,
        1376
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5995af10-bfe3-4ea0-ac6a-6e218bfa36da",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.isBounced }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "599b271f-a57d-487e-a5f3-2408f0045556",
      "name": "Step 34: Update Reason Type of email in Blacklisted Email Addresses",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2672,
        1376
      ],
      "parameters": {
        "url": "={{ $node['Step 2: Set Variables'].json.mail_blacklist_web_save }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"id\": 71,\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"call\",\n  \"params\": {\n    \"model\": \"mail.blacklist\",\n    \"method\": \"web_save\",\n    \"args\": [\n      [\n        {{ $node['Step 33: If list_ids = true'].json.id }}\n      ],\n      {\n        \"reason_type\": \"bounced\"\n      }\n    ],\n    \"kwargs\": {\n      \"context\": {\n        \"lang\": \"en_US\",\n        \"tz\": \"Asia/Bangkok\",\n        \"allowed_company_ids\": [\n          1\n        ],\n        \"params\": {\n          \"actionStack\": [\n            {\n              \"displayName\": \"Blacklisted Email Addresses\",\n              \"action\": 147,\n              \"view_type\": \"list\"\n            }\n          ],\n          \"action\": 147,\n          \"globalState\": {\n            \"searchModel\": \"{\\\"nextGroupId\\\":4,\\\"nextGroupNumber\\\":5,\\\"nextId\\\":4,\\\"query\\\":[],\\\"searchItems\\\":{\\\"1\\\":{\\\"type\\\":\\\"field\\\",\\\"fieldName\\\":\\\"email\\\",\\\"fieldType\\\":\\\"char\\\",\\\"description\\\":\\\"Email Address\\\",\\\"groupId\\\":1,\\\"id\\\":1},\\\"2\\\":{\\\"type\\\":\\\"filter\\\",\\\"domain\\\":\\\"[('active','=',False)]\\\",\\\"groupNumber\\\":2,\\\"name\\\":\\\"inactive\\\",\\\"description\\\":\\\"Archived\\\",\\\"groupId\\\":2,\\\"id\\\":2},\\\"3\\\":{\\\"type\\\":\\\"groupBy\\\",\\\"fieldName\\\":\\\"opt_out_reason_id\\\",\\\"fieldType\\\":\\\"many2one\\\",\\\"groupNumber\\\":4,\\\"name\\\":\\\"group_by_opt_out_reason_id\\\",\\\"description\\\":\\\"Reason\\\",\\\"groupId\\\":3,\\\"id\\\":3}},\\\"searchPanelInfo\\\":{\\\"className\\\":\\\"\\\",\\\"fold\\\":false,\\\"viewTypes\\\":[\\\"kanban\\\",\\\"list\\\"],\\\"loaded\\\":false,\\\"shouldReload\\\":true},\\\"sections\\\":[]}\"\n          }\n        }\n      },\n      \"specification\": {\n        \"email\": {},\n        \"id_contact_hubspot\": {},\n        \"reason_type\": {},\n        \"opt_out_reason_id\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"active\": {},\n        \"display_name\": {}\n      }\n    }\n  }\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "retryOnFail": true,
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "88e9774e-2ad8-420e-b9e8-ddea50d6b1f8",
      "name": "End1",
      "type": "n8n-nodes-base.noOp",
      "position": [
        1552,
        1408
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "f5c38d97-58ea-415b-b0cc-8017e90a2fae",
      "name": "End2",
      "type": "n8n-nodes-base.noOp",
      "position": [
        2000,
        1184
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "02dfebf5-61a0-4e98-b294-a6c894d69350",
      "name": "End3",
      "type": "n8n-nodes-base.noOp",
      "position": [
        3232,
        496
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "b3f1daea-35fe-46ce-8f3d-ebd85c94596f",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        592
      ],
      "parameters": {
        "color": 5,
        "width": 688,
        "height": 592,
        "content": "## 2. Loop Over the list of emails sent 10 days ago.\n- We can customize the number of days in \"Step 2: Set Variables\" using the days_ago field.\n- Each iteration checks if anyone has responded to the sent emails. After obtaining the results, they are categorized into lists: deliverableEmails, repliedEmails, bounceEmails, autoReplies, and noResponse.\n- After each iteration, the data is merged into the lists above."
      },
      "typeVersion": 1
    },
    {
      "id": "eb3c1e20-dbf9-4eec-9531-e688137724d9",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1616,
        144
      ],
      "parameters": {
        "width": 720,
        "height": 1744,
        "content": "# Email Contacts Sync from Sent Mailbox to Odoo\nThis workflow automatically extracts recipient email addresses from previously sent emails, validates and cleans the data, and synchronizes only deliverable contacts into the internal Odoo Mailing List. It also monitors replies and bounce signals to support follow-up and engagement tracking.\n## \ud83d\udcccWho is this for?\n- Marketing team (Email campaigns)\n- CRM / Odoo administrators\n- Sales team (follow-up & customer engagement)\n- Operations / Automation engineers (n8n workflows)\n\n## \ud83d\udcccThe problem\n- Customer emails are scattered across sent mail history instead of a centralized list.\n- Manually copying recipients into Odoo is slow and error-prone.\n- Sent emails may include invalid or bounced addresses.\n- Duplicate contacts appear frequently.\n- Hard to know which recipients have replied or not for follow-up.\n\n\nThis leads to:\n- messy contact database\n- high bounce rate\n- missed follow-ups\n- inefficient manual work\n\n## \ud83d\udcccHow it works\n- The system calculates the target date and queries the Gmail API to retrieve emails sent within the last X days.\n- For each sent email:\n         - Extract recipients from the To/Cc fields\n         - Normalize data (trim, lowercase, remove duplicates)\n         - Check the email thread to detect replies or bounce/system responses\n\n- Each recipient is then classified into one of the following lists:\n         - deliverableEmails\n         - repliedEmails\n         - bounceEmails\n         - autoReplies\n         - noResponse\n\n- Push the list of deliverable emails to the internal Odoo system as Mailing List Contacts.\n- Add emails from the bounce list to Blacklisted Email Addresses in Odoo to prevent future sending.\n- (Optional) Log all processing results into Google Sheets for tracking and auditing.\n\n## \ud83d\udcccQuick setup\nRequired information:\n- N8n Version 2.4.6\n- Gmail OAuth2 API\n- Odoo API-KEY\n\n\nGoogle Sheets will be used to log all notified events.\n\n## \ud83d\udcccResults\n- Automatically build contact list from real sent emails\n- No manual data entry\n- Only valid emails stored in Odoo\n- Reduced bounce rate\n- No duplicates\n- Easy follow-up tracking\n- Better CRM hygiene and campaign performance\n\n## \ud83d\udcccTake it further\n- Auto follow-up if no reply after X days\n- Auto-remove hard bounces\n- Engagement scoring\n- Reply analytics dashboard\n- Sync with Loyalty/CRM systems\n- Scheduled daily sync\n\n## \ud83d\udcccNeed help customizing?\nContact me for consulting and support:\n[Linkedin](https://www.linkedin.com/company/bac-ha-software/posts/?feedView=all) / [Website](https://bachasoftware.com/bhsoft-contacts)"
      },
      "typeVersion": 1
    },
    {
      "id": "679b5a96-57fa-49b6-96d4-d37111a86b14",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -848,
        672
      ],
      "parameters": {
        "color": 5,
        "width": 1392,
        "height": 512,
        "content": "## 1. Set Variables and Get datetime\n- Set Variables and Get datetime\n- Get the list of emails sent 10 days ago.\n- In Step 6, Split Out is used to split the \"messages\" array into multiple individual items."
      },
      "typeVersion": 1
    },
    {
      "id": "5a17590c-ead7-4b8c-95af-cf820e2b0b1d",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1264,
        352
      ],
      "parameters": {
        "color": 5,
        "width": 1312,
        "height": 640,
        "content": "## 3. Push the list of deliverable emails to the internal Odoo system.\n- For each email in the deliverable emails list, we check if it exists in the internal Odoo system.\n- If not, create a new contact and tag it as \"020.Good-to-send\".\n- If yes, ensure it is assigned to \"020.Good-to-send\" and update when needed."
      },
      "typeVersion": 1
    },
    {
      "id": "a187d542-9aa6-402e-a53c-cdd444cd9ff3",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2592,
        352
      ],
      "parameters": {
        "color": 5,
        "width": 1440,
        "height": 640,
        "content": "## 4. Add emails from the bounce email list to the \"Blacklisted Email Addresses\" in the internal Odoo system.\n- For each email in the bounce email list, we check if it exists in the internal Odoo system.\n- If not, create a new contact in the \"Blacklisted Email Addresses\" and tag it as \"bounced\".\n- If yes, ensure it is assigned to \"bounced\" and update when needed."
      },
      "typeVersion": 1
    },
    {
      "id": "9ccf3eee-9ab8-4987-875d-780694dc675c",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1264,
        1008
      ],
      "parameters": {
        "color": 5,
        "width": 1584,
        "height": 656,
        "content": "## 5. Same.....Add emails from the bounce email list to the \"Blacklisted Email Addresses\" in the internal Odoo system.\n- For each email in the bounce email list, we check if it exists in the internal Odoo system.\n- If not, create a new contact in the \"Blacklisted Email Addresses\" and tag it as \"bounced\".\n- If yes, ensure it is assigned to \"bounced\" and update when needed."
      },
      "typeVersion": 1
    },
    {
      "id": "2a5e0291-4bdb-4d42-b2be-bb90c21e5783",
      "name": "Step 11: If has record deliverableEmails",
      "type": "n8n-nodes-base.if",
      "position": [
        1072,
        784
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "45a079bb-5e20-4741-9b20-0031799fe2b4",
              "operator": {
                "type": "array",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.deliverableEmails }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "aba0d981-46b9-4aa6-ac40-ff7580964570",
      "name": "Step 12: Split Out deliverableEmails list",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1328,
        640
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "deliverableEmails"
      },
      "typeVersion": 1
    },
    {
      "id": "e75870af-bc4a-4dce-b1f4-e9d41d71c549",
      "name": "Step 13: Loop Over deliverableEmails",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1584,
        512
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    }
  ],
  "active": false,
  "settings": {
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "ef08c148-3b32-42f5-a7fd-96043e5bc39f",
  "connections": {
    "Step 2: Set Variables": {
      "main": [
        [
          {
            "node": "Step 3: Get date time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 3: Get date time": {
      "main": [
        [
          {
            "node": "Step 4:Get the list of emails sent 10 days ago.",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 17: If list_ids = true": {
      "main": [
        [
          {
            "node": "Step 13: Loop Over deliverableEmails",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step 18: Update email in Mailing List Contacts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 25: If list_ids = true": {
      "main": [
        [
          {
            "node": "Step 21: Loop Over bounceEmails",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step 26: Update Reason Type of email in Blacklisted Email Addresses",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 33: If list_ids = true": {
      "main": [
        [
          {
            "node": "Step 29: Loop Over bounceEmails",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step 34: Update Reason Type of email in Blacklisted Email Addresses",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 7: Loop Over email sent": {
      "main": [
        [
          {
            "node": "Step 10: Merge the categorized mailing lists",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step 8: Get email information about thread_id",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 6: Split Out emails sent": {
      "main": [
        [
          {
            "node": "Step 7: Loop Over email sent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 20: Split Out bounceEmails": {
      "main": [
        [
          {
            "node": "Step 21: Loop Over bounceEmails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 21: Loop Over bounceEmails": {
      "main": [
        [
          {
            "node": "End3",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step 22: Search email in Blacklisted Email Addresses",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 28: Split Out bounceEmails": {
      "main": [
        [
          {
            "node": "Step 29: Loop Over bounceEmails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 29: Loop Over bounceEmails": {
      "main": [
        [
          {
            "node": "End2",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step 30: Search email in Blacklisted Email Addresses",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 27: If has record bounceEmails": {
      "main": [
        [
          {
            "node": "Step 28: Split Out bounceEmails",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "End1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 13: Loop Over deliverableEmails": {
      "main": [
        [
          {
            "node": "Step 19: Return all data from step 10.",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step 14: Search email in Mailing List Contacts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 19: Return all data from step 10.": {
      "main": [
        [
          {
            "node": "Step 20: Split Out bounceEmails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 11: If has record deliverableEmails": {
      "main": [
        [
          {
            "node": "Step 12: Split Out deliverableEmails list",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step 27: If has record bounceEmails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 12: Split Out deliverableEmails list": {
      "main": [
        [
          {
            "node": "Step 13: Loop Over deliverableEmails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 1: Schedule Trigger every day at 7 AM": {
      "main": [
        [
          {
            "node": "Step 2: Set Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 9: Handling mail sorting from headers": {
      "main": [
        [
          {
            "node": "Step 7: Loop Over email sent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 10: Merge the categorized mailing lists": {
      "main": [
        [
          {
            "node": "Step 11: If has record deliverableEmails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 15: If number of records is not 0 = true": {
      "main": [
        [
          {
            "node": "Step 16.1\" Check if list_ids contains 020.Good-to-send",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step 16.2: Add new email in Mailing List Contacts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 23: If number of records is not 0 = true": {
      "main": [
        [
          {
            "node": "Step 24.1\" Check if reason_type contains Bounced",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step 24.2: Add new email in Blacklisted Email Addresses",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 31: If number of records is not 0 = true": {
      "main": [
        [
          {
            "node": "Step 32.1: Check if reason_type contains Bounced",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step 32.2: Add new email in Blacklisted Email Addresses",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 8: Get email information about thread_id": {
      "main": [
        [
          {
            "node": "Step 9: Handling mail sorting from headers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 14: Search email in Mailing List Contacts": {
      "main": [
        [
          {
            "node": "Step 15: If number of records is not 0 = true",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 18: Update email in Mailing List Contacts": {
      "main": [
        [
          {
            "node": "Step 13: Loop Over deliverableEmails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 4:Get the list of emails sent 10 days ago.": {
      "main": [
        [
          {
            "node": "Step 5: If resultSizeEstimate has a record ==> true",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 24.1\" Check if reason_type contains Bounced": {
      "main": [
        [
          {
            "node": "Step 25: If list_ids = true",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 32.1: Check if reason_type contains Bounced": {
      "main": [
        [
          {
            "node": "Step 33: If list_ids = true",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 16.2: Add new email in Mailing List Contacts": {
      "main": [
        [
          {
            "node": "Step 13: Loop Over deliverableEmails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 5: If resultSizeEstimate has a record ==> true": {
      "main": [
        [
          {
            "node": "Step 6: Split Out emails sent",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "End",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 22: Search email in Blacklisted Email Addresses": {
      "main": [
        [
          {
            "node": "Step 23: If number of records is not 0 = true",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 30: Search email in Blacklisted Email Addresses": {
      "main": [
        [
          {
            "node": "Step 31: If number of records is not 0 = true",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 16.1\" Check if list_ids contains 020.Good-to-send": {
      "main": [
        [
          {
            "node": "Step 17: If list_ids = true",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 24.2: Add new email in Blacklisted Email Addresses": {
      "main": [
        [
          {
            "node": "Step 21: Loop Over bounceEmails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 32.2: Add new email in Blacklisted Email Addresses": {
      "main": [
        [
          {
            "node": "Step 29: Loop Over bounceEmails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 26: Update Reason Type of email in Blacklisted Email Addresses": {
      "main": [
        [
          {
            "node": "Step 21: Loop Over bounceEmails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step 34: Update Reason Type of email in Blacklisted Email Addresses": {
      "main": [
        [
          {
            "node": "Step 29: Loop Over bounceEmails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}