> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.meetgail.com/platform/workflows/guides-and-recipes/guides/process-a-daily-csv/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.meetgail.com/_mcp/server. # Process a Daily CSV > Build a workflow that pulls a partner's daily lead file from SFTP every morning and adds each row as a contact. Plenty of partners drop a file of new leads on a server every night. This guide builds a workflow that runs each morning, downloads that file, reads it row by row, and adds every lead as a contact, all on its own. The workflow has these steps, running top to bottom: Start, then SFTP Download, then Parse CSV, then a For Each loop that runs Add Contact for every row, then End. ![The Process Daily CSV workflow on the builder canvas: Start, SFTP Download, Parse CSV, a For Each loop containing Add Contact, End.](/_fern-img/0a549c62dbffb87887b574ef656ed9e5a7b436cf8b1bd03664a4632c19a9e7a5.webp) ## What each step does * **Start** is a scheduled trigger that runs the workflow once a day. * **SFTP Download** connects to the partner's server and pulls down the file. * **Parse CSV** turns the downloaded file into a list of rows. * **For Each** loops over the rows and runs Add Contact for each one. * **End** finishes the run. ## Build it step by step ### Set the Start step to run on a schedule Configure the Start step as a scheduled trigger so the workflow runs every morning without anyone kicking it off. See [Triggers & Webhooks](/platform/workflows/core-concepts/triggers-webhooks) for how triggers are set up. ### Add the SFTP Download step Add an [SFTP Download](/platform/workflows/node-reference/integrations/sftp/sftp-download) step below Start and point it at the partner's server: | Field | What to enter | | ---------------------- | -------------------------------------- | | Host | `sftp.example.com` | | Port | `22` | | Username | `gail-imports` | | Remote Path | `/exports/leads-daily.csv` | | Password / Private Key | Choose a stored secret from the picker | > **Note** > > Never type a password or private key into a step. The credential fields on > SFTP Download show a secret picker, not a text box, so the value comes from a > stored secret and stays out of the workflow. Set one up first. See > [Secrets](/platform/workflows/core-concepts/secrets). ![The SFTP Download settings panel: host, port, username, remote path, and secret pickers for the password and private key.](/_fern-img/b801630192e945e0fb0ec579168b9ee70e4d6df6ebdafe7e8c001b882c5364d4.webp) ### Add the Parse CSV step Add a [Parse CSV](/platform/workflows/node-reference/files-and-documents/parse-csv) step below SFTP Download. For the **CSV file** field, point it at the file the download produced: ``` sftp-download.data.file ``` Turn the "first row is a header" option on, so the column names come from the top row of the file. ![The Parse CSV settings panel: the CSV file set to sftp-download.data.file with first-row-is-a-header turned on.](/_fern-img/62b86ad74ae47b162c1816c4fb8c588562af90dd01ba9da79db33179d80c3acc.webp) ### Add the For Each loop Add a [For Each](/platform/workflows/node-reference/logic-and-flow/for-each) step below Parse CSV. For the **Collection** field, point it at the parsed rows: ``` parse-csv.data.rows ``` ### Add Add Contact inside the loop Inside the For Each loop, add an [Add Contact](/platform/workflows/node-reference/gail/add-contact) step. Inside a loop, the current row is available as `_each_.item`, so read each column from it: | Field | Expression | | ------------- | ------------------------ | | First name | `_each_.item.first_name` | | Last name | `_each_.item.last_name` | | Email | `_each_.item.email` | | Phone number | `_each_.item.phone` | | Business name | `_each_.item.business` | The column names after `item` match the header row of your file, so adjust them to whatever the partner's file uses. ### Connect the steps and save Connect Start to SFTP Download to Parse CSV to For Each to End, then save. ![The For Each settings panel: the collection set to parse-csv.data.rows with the collect-results option.](/_fern-img/b9c25d0f82b5e1eace422996e15fef110081881a32a3369d3115f41d2645e3fc.webp) > **Note** > > For Each has a "collect results" option that gathers every pass's output into a > list. Leave it off for large loops like a daily import; a long list of results > can grow large fast, and each pass is still visible in the run history either > way. ## What to try next #### [Loop Over a CSV](/platform/workflows/guides-and-recipes/recipes/loop-over-a-csv) The short version of the parse-then-loop pattern. #### [Branch on a Value](/platform/workflows/guides-and-recipes/recipes/branch-on-a-value) Skip or route rows that do not meet a condition. #### [Append to Google Sheets](/platform/workflows/guides-and-recipes/recipes/append-to-google-sheets) Log each imported row to a spreadsheet as it goes. #### [Welcome New Leads](/platform/workflows/guides-and-recipes/guides/welcome-new-leads) Greet each new lead the moment they arrive. > Documentation for Gail, the AI platform for financial services. Learn how to set up GailGPT and Gail Agent to automate customer communications for insurance, banking, and finance.