Importar contatos do Google Sheets para a Brevo com Apps Script

Exemplo repetível de Google Apps Script que verifica consentimento, mapeia campos, preserva descadastros e mostra erros da API da Brevo.

google apps script brevo

Qual é a resposta curta?

Adicione as colunas email, firstName, lastName e consent à planilha. Defina BREVO_API_KEY nas propriedades do script e o ID da lista no código; depois execute syncSheetToBrevo. O script considera apenas linhas com consentimento, verifica descadastros na Brevo, remove duplicatas e para em erros da API. É um Apps Script mantido por você, não um conector nativo.

Saiba mais
Nesta página

Uma planilha com doze inscrições para um evento é fácil de exportar uma vez. Na segunda importação, um endereço aparece duas vezes e outra pessoa já se descadastrou na Brevo. Uma importação repetível precisa detectar ambos os casos.

Este script usa os endpoints da Brevo para ler, criar e atualizar contatos. Ele serve para pequenas importações agendadas, não para cargas em massa nem como conector nativo do Google Sheets. Não envia e-mail. A prova de consentimento e a operação do script são suas responsabilidades.

Prepare a planilha e a lista

Crie uma aba Contacts com estes cabeçalhos exatos. Use caixas de seleção para consent e marque TRUE apenas quando houver permissão para o uso de marketing previsto.

emailfirstNamelastNameconsent
[email protected]JaneDoeTRUE
[email protected]AlexLeeFALSE

Crie ou escolha uma lista na Brevo e copie o ID numérico para LIST_ID no código. Confirme que os atributos FNAME e LNAME existem na Brevo. São os únicos campos mapeados. Guarde o registro de quando e como o consentimento foi obtido se a planilha não puder comprová-lo. Uma célula TRUE não é prova suficiente.

Em Extensões → Apps Script → Configurações do projeto → Propriedades do script, adicione BREVO_API_KEY. Essas propriedades são compartilhadas entre usuários do script; limite quem pode editá-lo. Não guarde a chave em uma célula nem no código-fonte. Veja as regras de acesso do Google.

O script

Substitua Code.gs por este exemplo e ajuste LIST_ID antes da primeira execução.

const LIST_ID = 42; // Replace with your existing Brevo list ID.
const TAB = 'Contacts';
const BASE = 'https://api.brevo.com/v3';
function syncSheetToBrevo() {
const key = PropertiesService.getScriptProperties().getProperty('BREVO_API_KEY');
if (!key) throw new Error('Set BREVO_API_KEY in Script Properties first');
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(TAB);
if (!sheet) throw new Error('Contacts tab missing');
const values = sheet.getDataRange().getValues();
const headers = values.shift().map(h => String(h).trim());
const columns = ['email', 'firstName', 'lastName', 'consent']
.map(name => headers.indexOf(name));
if (columns.includes(-1)) throw new Error('Required header missing');
const [emailCol, firstCol, lastCol, consentCol] = columns;
const seen = new Set();
const result = { written: 0, skipped: 0 };
for (const row of values) {
const email = String(row[emailCol] || '').trim().toLowerCase();
if (row[consentCol] !== true || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) || seen.has(email)) {
result.skipped++;
continue;
}
seen.add(email);
const path = '/contacts/' + encodeURIComponent(email);
const current = brevo_(key, path, 'get');
if (current.code !== 200 && current.code !== 404) {
throw new Error(`Contact read failed (${current.code}) for row ${result.written + result.skipped + 2}`);
}
if (current.code === 200) {
const contact = JSON.parse(current.text);
if (contact.emailBlacklisted || (contact.listUnsubscribed || []).includes(LIST_ID)) {
result.skipped++;
continue;
}
}
const attributes = {};
if (row[firstCol] !== '') attributes.FNAME = String(row[firstCol]);
if (row[lastCol] !== '') attributes.LNAME = String(row[lastCol]);
const body = { attributes, listIds: [LIST_ID] };
const saved = current.code === 404
? brevo_(key, '/contacts', 'post', { email, ...body })
: brevo_(key, path, 'put', body);
if (![201, 204].includes(saved.code)) {
throw new Error(`Contact write failed (${saved.code}) for ${email}: ${saved.text.slice(0, 200)}`);
}
result.written++;
}
Logger.log(JSON.stringify(result));
return result;
}
function brevo_(key, path, method, body) {
for (let attempt = 0; attempt < 3; attempt++) {
const response = UrlFetchApp.fetch(BASE + path, {
method,
contentType: 'application/json',
headers: { 'api-key': key },
payload: body ? JSON.stringify(body) : undefined,
muteHttpExceptions: true,
});
const code = response.getResponseCode();
if (code !== 429) return { code, text: response.getContentText() };
if (attempt === 2) return { code, text: response.getContentText() };
const reset = Object.entries(response.getHeaders()).find(
([name]) => name.toLowerCase() === 'x-sib-ratelimit-reset'
);
const raw = Number(reset && reset[1]);
const seconds = Number.isFinite(raw) && raw > 0 ? raw : 2 ** attempt;
const waitSeconds = seconds + 2 ** attempt;
if (waitSeconds > 60) return { code, text: response.getContentText() };
Utilities.sleep(waitSeconds * 1000);
}
}

Salve, selecione syncSheetToBrevo e clique em Executar. O Google pedirá acesso ao Sheets e a solicitações externas. Em Execuções, veja o registro final {written, skipped}. Uma leitura 404 leva à criação; uma 200 leva à atualização. Outros erros interrompem a execução. Uma gravação bem-sucedida confirma a requisição de contato, não o envio de campanha.

O script elimina e-mails repetidos na mesma execução e consulta a Brevo novamente na próxima. Nunca define emailBlacklisted como false nem altera o e-mail. Se a Brevo indicar bloqueio global ou descadastro dessa lista, a linha será ignorada mesmo que a planilha mostre TRUE. Não use o script para reverter um descadastro. A Brevo alerta que alterar o endereço de um contato bloqueado pode remover o bloqueio.

Confira uma execução antes de agendar

Use uma lista de teste e contatos que você controla. Rode com uma linha TRUE, uma FALSE e um e-mail duplicado: espere uma gravação e duas linhas ignoradas. Descadastre o contato de teste na Brevo e rode outra vez: ele não deve receber gravação. Para testar uma falha, ajuste LIST_ID temporariamente para um valor inválido, confira o erro HTTP em Execuções, restaure o ID e repita. Não teste com clientes reais. O código também foi validado localmente com respostas simuladas da Brevo, sem gravação ao vivo.

Para agendar, abra Apps Script → Acionadores → Adicionar acionador, escolha syncSheetToBrevo e um intervalo baseado em tempo. Acionadores instaláveis rodam na conta de quem os criou, que precisa manter acesso à planilha. Comece diariamente para uma planilha pequena e confira falhas. O Google limita duração e chamadas URL Fetch; divida fontes grandes em trabalhos limitados.

Ao receber 429, o script lê x-sib-ratelimit-reset, faz no máximo duas novas tentativas e retorna 429 para uma execução posterior se a espera necessária superar 60 segundos. Outros erros param a execução; a próxima rodada começa do início. Um contato pode se descadastrar entre a leitura e a gravação. Use este exemplo somente se essa pequena janela for aceitável. Para garantias mais fortes, combine reconciliação por eventos, uma fonte confiável de consentimento e uma última checagem antes do envio.

Para planilhas grandes, o endpoint de importação assíncrona da Brevo devolve processId. Ele confirma que um trabalho foi aceito, não que terminou. Confira o resultado antes de declarar a importação bem-sucedida. O caminho por contato deste artigo mostra a falha na linha que a causou.

Perguntas frequentes

É necessário um conector nativo do Google Sheets?

Não. O exemplo roda em um projeto Google Apps Script vinculado à planilha e chama a API de contatos da Brevo. Você mantém o script, a chave de API e o acionador agendado.

Quais linhas são enviadas à Brevo?

Somente linhas com TRUE em consent e e-mail válido. O script remove duplicatas em cada execução e consulta a Brevo antes de escrever.

Uma nova execução reinscreve quem se descadastrou?

O script ignora contatos que a Brevo marca como emailBlacklisted ou descadastrados da lista de destino. Ele nunca envia emailBlacklisted: false nem muda o endereço de e-mail. Verifique outras fontes de consentimento antes de usar em produção.

Como repetir uma execução com falha?

Leia o erro nas execuções do Apps Script, corrija a causa e execute a mesma função de novo. As gravações usam o mesmo e-mail e ID de lista; uma linha já concluída não cria um segundo contato.

Solicite acesso antecipado

Indique o seu nome e endereço de e-mail profissional. Enviaremos um link para confirmar o seu pedido de acesso ao Tajo.

Obter Brevo