Saving HTML as file in Google Drive

I have a workflow which summarizes CNN News into an HTML table.

The table is created but I cannot figure out how to upload it to Google Drive.

I get an error saying “This operation expects the node’s input to contain a binary file 'htmlFile” but none was found."

How do I create a binary file?

{
  "name": "CNN RSS Summary",
  "nodes": [
    {
      "parameters": {
        "url": "http://rss.cnn.com/rss/edition.rss",
        "options": {}
      },
      "name": "HTTP Request",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        304,
        208
      ],
      "id": "generated-97b20896-1ff1-4768-a996-0b5e3cfedd7f"
    },
    {
      "parameters": {
        "options": {
          "attrkey": "$",
          "charkey": "_",
          "explicitArray": false,
          "explicitRoot": true,
          "ignoreAttrs": false,
          "mergeAttrs": true,
          "normalize": false,
          "normalizeTags": false,
          "trim": false
        }
      },
      "name": "Parse XML",
      "type": "n8n-nodes-base.xml",
      "position": [
        528,
        208
      ],
      "id": "generated-49bde392-11de-4b76-a647-26e5ad4f1c05"
    },
    {
      "parameters": {
        "functionCode": "// Get the array of articles from the parsed RSS feed\nconst items = $json.rss.channel.item;\n\n// If only one article, wrap in array\nconst articles = Array.isArray(items) ? items : [items];\n\n// Take the first 10 articles\nreturn articles.slice(0, 10).map(article => ({ json: article }));"
      },
      "name": "Extract Top 10 Articles",
      "type": "n8n-nodes-base.function",
      "position": [
        752,
        208
      ],
      "id": "generated-a34dfdad-911d-4a34-80d6-5694cacd8b3c"
    },
    {
      "parameters": {
        "fromEmail": "[email protected]",
        "toEmail": "[email protected]",
        "subject": "CNN RSS News Summary",
        "emailFormat": "text",
        "options": {
          "appendAttribution": true,
          "attachments": "=\n",
          "ccEmail": "",
          "bccEmail": "",
          "allowUnauthorizedCerts": false,
          "replyTo": ""
        }
      },
      "name": "Send Email (SMTP)",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        1888,
        208
      ],
      "id": "generated-b04c4190-e04e-46d4-bb81-6b5ef64157bd",
      "webhookId": "042acfc7-50d0-4317-ab4d-382eff21977f",
      "credentials": {
        "smtp": {
          "id": "X5rhsRBwTsi3OyqS",
          "name": "SMTP account"
        }
      }
    },
    {
      "parameters": {
        "content": "## CNN RSS Email Summary Workflow\n\n1. **HTTP Request**: Fetches CNN RSS feed.\n2. **Parse XML**: Converts XML to JSON.\n3. **Extract Top 10 Articles**: Selects the 10 most recent articles.\n4. **Summarize with OpenAI**: Summarizes each article (bullets, pros, cons).\n5. **Build HTML Table**: Formats results as a styled HTML table.\n6. **Send Email (SMTP)**: Emails the HTML table to [email protected].\n\n⚡ You can schedule this workflow with a trigger node for automation!",
        "height": 340,
        "width": 600,
        "color": 5
      },
      "name": "Workflow Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        848,
        48
      ],
      "id": "generated-7b9da9b7-4456-4f0b-8c67-cd4f261fd885"
    },
    {
      "parameters": {},
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        80,
        208
      ],
      "id": "generated-9d16467f-e989-4101-b3d5-e7b07c8ed620"
    },
    {
      "parameters": {
        "options": {
          "summarizationMethodAndPrompts": {
            "values": {
              "combineMapPrompt": "Write a concise summary of the following article. Provide:\n- 3-5 bullet points summarizing the main content\n- 2-3 pros\n- 2-3 cons\n\n\"{text}\"\n\nCONCISE SUMMARY BULLETS:\nPROS:\nCONS:",
              "prompt": "Write a concise summary of the following article. Provide:\n- 3-5 bullet points summarizing the main content\n- 2-3 pros\n- 2-3 cons\n\n\"{text}\"\n\nCONCISE SUMMARY BULLETS:\nPROS:\nCONS:"
            }
          }
        }
      },
      "type": "@n8n/n8n-nodes-langchain.chainSummarization",
      "typeVersion": 2.1,
      "position": [
        960,
        208
      ],
      "id": "9098e69d-d214-456b-aed0-ff42d54f2a5e",
      "name": "Summarization Chain",
      "alwaysOutputData": true
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini"
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.2,
      "position": [
        896,
        416
      ],
      "id": "53f283ec-4956-40d6-bd5b-df3ce8d8f2bc",
      "name": "OpenAI Chat Model",
      "credentials": {
        "openAiApi": {
          "id": "xjEGLjNNtlk2c7OM",
          "name": "OpenAi account"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Create HTML file for Google Drive upload\nlet html = `<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"UTF-8\">\n    <title>CNN RSS News Summary - ${new Date().toLocaleDateString()}</title>\n    <style>\n        body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }\n        .container { max-width: 1200px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; }\n        h1 { color: #003366; text-align: center; }\n        table { border-collapse: collapse; width: 100%; }\n        th, td { border: 1px solid #ddd; padding: 12px; vertical-align: top; }\n        th { background: #003366; color: #fff; }\n        tr:nth-child(even) { background: #f9f9f9; }\n        ul { margin: 0; padding-left: 20px; }\n    </style>\n</head>\n<body>\n    <div class=\"container\">\n        <h1>CNN RSS News Summary</h1>\n        <p style=\"text-align: center; color: #666;\">Generated on: ${new Date().toLocaleDateString()}</p>\n        <table>\n            <tr><th>Article #</th><th>Summary</th><th>Pros</th><th>Cons</th></tr>`;\n\nfor (let i = 0; i < items.length; i++) {\n    const item = items[i];\n    const fullSummaryText = item?.json?.output?.text || '';\n    const title = `${i + 1}`;\n    \n    let summaryBullets = 'No summary available';\n    let pros = 'No pros identified';\n    let cons = 'No cons identified';\n\n    if (fullSummaryText) {\n        const sections = fullSummaryText.split(/\\n\\n/);\n        \n        for (const section of sections) {\n            const lines = section.trim().split('\\n');\n            \n            if (lines[0].includes('SUMMARY BULLETS')) {\n                const bulletLines = lines.slice(1).filter(line => line.trim().startsWith('-'));\n                if (bulletLines.length > 0) {\n                    summaryBullets = '<ul>' + bulletLines.map(line => \n                        `<li>${line.trim().substring(1).trim()}</li>`\n                    ).join('') + '</ul>';\n                }\n            } else if (lines[0].includes('PROS')) {\n                const prosLinesList = lines.slice(1).filter(line => line.trim().startsWith('-'));\n                if (prosLinesList.length > 0) {\n                    pros = '<ul>' + prosLinesList.map(line => \n                        `<li>${line.trim().substring(1).trim()}</li>`\n                    ).join('') + '</ul>';\n                }\n            } else if (lines[0].includes('CONS')) {\n                const consLinesList = lines.slice(1).filter(line => line.trim().startsWith('-'));\n                if (consLinesList.length > 0) {\n                    cons = '<ul>' + consLinesList.map(line => \n                        `<li>${line.trim().substring(1).trim()}</li>`\n                    ).join('') + '</ul>';\n                }\n            }\n        }\n    }\n\n    html += `<tr><td style=\"text-align: center; font-weight: bold;\">${title}</td><td>${summaryBullets}</td><td>${pros}</td><td>${cons}</td></tr>`;\n}\n\nhtml += `</table></div></body></html>`;\n\nconst filename = `CNN_Summary_${new Date().toISOString().split('T')[0]}.html`;\n\nreturn [{\n    json: {\n        htmlFile: html,\n        filename: filename,\n        emailBody: `Your CNN RSS News Summary is ready!\\n\\nThe HTML report has been saved to Google Drive as: ${filename}\\n\\nTo view: Go to https://drive.google.com and open the file.\\n\\nThis summary contains ${items.length} articles with full analysis.\\n\\nBest regards,\\nNews Bot`\n    }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1344,
        208
      ],
      "id": "e73451c3-9c07-4d1f-86d3-d1d951744ba5",
      "name": "Build HTML Table"
    },
    {
      "parameters": {
        "operation": "createFromText",
        "content": "htmlFile",
        "name": "CNN_Summary.html",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "root",
          "cachedResultName": "/ (Root folder)"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        1712,
        208
      ],
      "id": "ae1b022d-60dd-48ae-82b8-f1cdb42edbb6",
      "name": "Create file from text",
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "vl5QRzFIsYJctiJr",
          "name": "Google Drive account"
        }
      }
    },
    {
      "parameters": {
        "inputDataFieldName": "htmlFile",
        "name": "CNN_News_Summary_File.html",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "root",
          "cachedResultName": "/ (Root folder)"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        1552,
        208
      ],
      "id": "874554bc-ec2b-4d60-b8dd-a552c2706bd6",
      "name": "Upload file",
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "vl5QRzFIsYJctiJr",
          "name": "Google Drive account"
        }
      }
    }
  ],
  "pinData": {},
  "connections": {
    "HTTP Request": {
      "main": [
        [
          {
            "node": "Parse XML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse XML": {
      "main": [
        [
          {
            "node": "Extract Top 10 Articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Top 10 Articles": {
      "main": [
        [
          {
            "node": "Summarization Chain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Summarization Chain": {
      "main": [
        [
          {
            "node": "Build HTML Table",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Summarization Chain",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Build HTML Table": {
      "main": [
        [
          {
            "node": "Upload file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create file from text": {
      "main": [
        [
          {
            "node": "Send Email (SMTP)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload file": {
      "main": [
        [
          {
            "node": "Create file from text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "c992cba0-a9d8-40e5-9d59-63d30117eeeb",
  "meta": {
    "templateCredsSetupCompleted": true,
    "instanceId": "ddc8b19b7fa20047424f31044d87873eaee7496fb5be5378767f1db53a15213a"
  },
  "id": "b9JWzibNlwNVIvqW",
  "tags": []
}```

Hey @rkaplan hope all is well.

You first need to convert html text into binary. Try this:

Alternatively you could create the file from the text using the functionality of the Google Drive itself.

What is it you wish to do after saving the file to Google Drive?

1 Like

Thank you @jabbson

I added the Convert to File node

It is very close - it does create a file with HTML markup. But when I open it in Google Chrome I see the HTML markup rather than rendered HTML.

What I want is an HTML file that I can easily view in rendered format in a browser. How can I do that?

You can review it in the email, if you send it in HTML format for example:

That works quite welll displaying in email - many thanks

Out of curiosity - do you know why the saved html file opens as text rahter than as rendered HTML?

Google Drive is a storage solution and not an html markdown rendering engine would be my best guess :slight_smile:

Another way to preview your html would be in the n8n itself:

If this was helpful, please mark the most helpful answer as solution.
Thank you.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.