Solução completa · Excel e Office Scripts

CSV recebido por e-mail para tabela do Excel, sem loop

Em vez de percorrer o arquivo linha por linha, o fluxo entrega o texto inteiro do CSV a um Office Script, que grava tudo na tabela de uma vez. Menos ações, menos risco de 429 e muito mais rápido.

O problema

Toda manhã chega um e-mail com um CSV (vendas do dia, estoque, extrato) e alguém copia as linhas para uma planilha. A solução ingênua automatiza isso com um Aplicar a cada: para cada linha do CSV, uma ação Adicionar linha a uma tabela. Funciona com 20 linhas e vira um pesadelo com 5.000: cada linha é uma ação, o fluxo demora, consome o limite de ações e, no pior caso, atinge o erro 429.

A alternativa é entregar o CSV inteiro a um Office Script, um pequeno código que roda dentro do Excel na web e grava todas as linhas em lote. Para o fluxo, é uma única ação.

O que você precisa

Passo 1: crie o script

No Excel na web, abra Automatizar > Novo script > Criar no editor de código, apague o conteúdo e cole o código abaixo. Salve com o nome Gravar CSV na tabela.

function main(
  workbook: ExcelScript.Workbook,
  csv: string,
  tableName: string = "TabelaDados"
): string {
  const table = workbook.getTable(tableName);
  if (!table) {
    throw new Error("Tabela não encontrada: " + tableName);
  }
  const rows = parseCsv(csv);
  if (rows.length < 2) {
    return "O CSV não tem linhas de dados.";
  }
  const columns = table.getColumns().length;
  const data = rows.slice(1).map((r) => normalize(r, columns));
  // Grava em blocos de 500 linhas para ficar longe dos limites de tamanho
  for (let i = 0; i < data.length; i += 500) {
    table.addRows(-1, data.slice(i, i + 500));
  }
  return data.length + " linhas adicionadas.";
}

// ---- leitura do CSV (testada fora do Excel) ----
function normalize(row: string[], size: number): string[] {
  const out = row.slice(0, size);
  while (out.length < size) {
    out.push("");
  }
  return out;
}

function parseCsv(text: string): string[][] {
  const clean = text.replace(/^/, "");
  const firstLine = clean.split(/\r?\n/)[0] || "";
  const counts: { [key: string]: number } = { ",": 0, ";": 0, "\t": 0 };
  let inQuotes = false;
  for (const ch of firstLine) {
    if (ch === '"') {
      inQuotes = !inQuotes;
    } else if (!inQuotes && ch in counts) {
      counts[ch]++;
    }
  }
  let delimiter = ",";
  let best = 0;
  for (const d of [",", ";", "\t"]) {
    if (counts[d] > best) {
      best = counts[d];
      delimiter = d;
    }
  }

  const rows: string[][] = [];
  let row: string[] = [];
  let value = "";
  let quoted = false;
  let fieldStart = true;
  for (let i = 0; i < clean.length; i++) {
    const c = clean[i];
    if (quoted) {
      if (c === '"') {
        if (clean[i + 1] === '"') {
          value += '"';
          i++;
        } else {
          quoted = false;
        }
      } else {
        value += c;
      }
    } else if (c === '"' && fieldStart) {
      quoted = true;
      fieldStart = false;
    } else if (c === delimiter) {
      row.push(value);
      value = "";
      fieldStart = true;
    } else if (c === "\n" || c === "\r") {
      if (c === "\r" && clean[i + 1] === "\n") {
        i++;
      }
      row.push(value);
      rows.push(row);
      row = [];
      value = "";
      fieldStart = true;
    } else {
      value += c;
      fieldStart = false;
    }
  }
  row.push(value);
  rows.push(row);
  return rows.filter((r) => r.some((cell) => cell !== ""));
}
Testado: a parte de leitura do CSV (parseCsv e normalize) é executada por testes automatizados do Me Ajuda Flow com vírgula, ponto e vírgula, Tab, aspas, aspas escapadas, quebra de linha dentro de aspas, BOM, linhas em branco e linhas mais curtas ou mais longas que a tabela. A gravação no Excel (main) segue a documentação oficial e deve ser testada no seu ambiente.

O que o script faz: lê o CSV (detecta sozinho se o separador é vírgula, ponto e vírgula ou Tab), ajusta cada linha ao número de colunas da tabela (completa com vazio ou descarta o excesso) e grava em blocos de 500 linhas.

Passo 2: monte o fluxo

  1. Gatilho: Office 365 Outlook, Quando um novo e-mail chegar (V3). Em Opções avançadas, deixe Somente com anexo = Sim e Incluir anexos = Sim. Filtre por remetente ou assunto, para o fluxo não disparar com qualquer e-mail.
  2. Filtrar matriz (para ignorar imagens de assinatura e outros anexos): em De, use triggerOutputs()?['body/attachments'] e, na condição avançada, endsWith(item()?['name'], '.csv'). Renomeie a ação para Filtrar_anexos.
  3. Executar script (Excel Online (Business)): escolha o arquivo pelo seletor, o script Gravar CSV na tabela e preencha os parâmetros. Em csv, use a expressão:
    base64ToString(first(body('Filtrar_anexos'))?['contentBytes'])
    Em tableName, escreva TabelaDados.
  4. Opcional: um e-mail ou uma mensagem no Teams confirmando, com o texto que o script devolve (quantas linhas foram adicionadas).
Acentos trocados? A conversão do anexo parte do princípio de que o arquivo está em UTF-8. Se aparecerem símbolos no lugar de acentos, o CSV de origem provavelmente foi salvo em Windows-1252 (testado: um anexo em Windows-1252 com a palavra "Olá" chega ao fluxo como "Ol�"). Salve (ou exporte) como "CSV UTF-8" na origem. Você pode conferir no conversor CSV para JSON, que reconhece as duas codificações.
Executado no Power Automate: as duas expressões de anexo foram executadas em 02/11/2026, em um fluxo de teste, com uma lista de dois anexos (assinatura.png e Vendas.CSV). O Filtrar matriz devolveu só o Vendas.CSV (o endsWith não diferencia .CSV de .csv), e base64ToString(first(body('Filtrar_anexos'))?['contentBytes']) devolveu o texto nome;valor e Ana;1,5, com a quebra de linha. A gravação no Excel pelo script não foi executada nesse teste.

Limites que você precisa conhecer

LimiteValor
Tamanho de requisição e resposta do Excel5 MB
Tamanho máximo dos parâmetros da ação Executar script30.000.000 bytes
Tempo máximo de uma operação síncrona do Power Automate120 segundos
Chamadas da ação Executar script por usuário1.600 por dia (zera às 00:00 UTC)
Chamadas externas (fetch) dentro do scriptNão funcionam no Power Automate

Para CSV muito grande, divida o arquivo ou chame o script mais de uma vez com partes menores. O script já grava em blocos para não estourar o limite de tamanho em uma única gravação.

Armadilhas

Como testar antes de confiar

  1. Envie para você mesmo um CSV pequeno (3 linhas), com acentos e uma célula com vírgula entre aspas.
  2. Abra a execução no histórico e confira a saída da ação Executar script: deve dizer "3 linhas adicionadas".
  3. Abra a tabela no Excel e confira acentos, colunas e valores.
  4. Só então teste com um arquivo real, e depois com um grande.

Ferramentas para usar com este guia

Fontes oficiais