Relatório Financeiro Automático no E-mail com Apps Script e IA
Nos posts anteriores, Como usar IA para planejar metas financeiras realistas e Automatizando o Planejamento de Metas com IA e Google Apps Script, você aprendeu a usar IA para definir metas financeiras realistas e a conectar sua planilha à API da OpenAI para gerar análises automáticas. Hoje fechamos o ciclo: vamos fazer o sistema enviar um relatório financeiro completo por e-mail, com as análises da IA, direto para a sua caixa de entrada — todo dia 1º do mês, sem precisar abrir o Google Sheets.
|
| Fonte: https://br.freepik.com/ |
O que será implementado
Ao final deste tutorial, sua planilha irá apresentar três novas funcionalidades no menu 🤖 Análise IA:
- Enviar relatório por e-mail — disparo manual com um clique
- Ativar envio automático mensal — configura um trigger (gatilho) para rodar todo dia 1º do mês às 08h
- Desativar envio automático — remove o trigger quando quiser pausar
O e-mail gerado inclui um resumo financeiro do mês, as três análises da IA (resumo, alertas e sugestões) e um indicador visual de status (🟢 Saudável, 🟡 Atenção ou 🔴 Crítico) baseado em regras que você mesmo define.
Pré-requisitos
- O código dos posts anteriores já instalado no Apps Script da planilha
- A chave da OpenAI já salva no PropertiesService
- A planilha com pelo menos a aba IA_Analises preenchida (rode 🤖 Análise IA → Analisar minhas metas uma vez antes)
O código Apps Script
const EMAIL_DESTINATARIO = Session.getActiveUser().getEmail(); // usa o e-mail do dono da planilha const LIMITE_ALERTA_COMPROMETIMENTO = 80; // % da renda — acima disso dispara alerta crítico const LIMITE_ALERTA_META = 50; // % de cumprimento das metas — abaixo disso dispara alerta
function onOpen() { SpreadsheetApp.getUi() .createMenu("🤖 Análise IA") .addItem("Analisar minhas metas", "analisarMetas") .addSeparator() .addItem("Enviar relatório por e-mail", "enviarRelatorioEmail") .addItem("Ativar envio automático mensal", "ativarTriggerMensal") .addItem("Desativar envio automático", "desativarTriggerMensal") .addToUi(); }
// ENVIO MANUAL DO RELATÓRIO function enviarRelatorioEmail() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const analises = lerAbaComoObjeto(ss, "IA_Analises"); const resumo = lerAbaComoObjeto(ss, "Resumo_Mensal"); const config = lerAbaComoObjeto(ss, "Configurações"); // Verifica se já existe análise gerada if (!analises["Resumo mensal"]) { SpreadsheetApp.getUi().alert("Nenhuma análise encontrada. Execute 'Analisar minhas metas' primeiro."); return; } const nivel = avaliarNivelAlerta(resumo, ss); const html = montarEmailHtml(config, analises, resumo, nivel); const assunto = montarAssunto(config, nivel); GmailApp.sendEmail(EMAIL_DESTINATARIO, assunto, "", { htmlBody: html }); SpreadsheetApp.getUi().alert(`✅ Relatório enviado para ${EMAIL_DESTINATARIO}`); } // FUNÇÃO CHAMADA PELO TRIGGER AUTOMÁTICO function enviarRelatorioAutomatico() { const ss = SpreadsheetApp.getActiveSpreadsheet(); // Roda a análise de IA antes de enviar analisarMetas(); const analises = lerAbaComoObjeto(ss, "IA_Analises"); const resumo = lerAbaComoObjeto(ss, "Resumo_Mensal"); const config = lerAbaComoObjeto(ss, "Configurações"); const nivel = avaliarNivelAlerta(resumo, ss); const html = montarEmailHtml(config, analises, resumo, nivel); const assunto = montarAssunto(config, nivel); GmailApp.sendEmail(EMAIL_DESTINATARIO, assunto, "", { htmlBody: html }); } // AVALIAÇÃO DO NÍVEL DE ALERTA function avaliarNivelAlerta(resumo, ss) { const comprometido = parseFloat(resumo["% da Renda Comprometida"]) || 0; const metas = lerAbaComoTabela(ss, "Metas_Mensais"); const metasComDesvio = metas.filter(m => { const ideal = parseFloat(m["Valor ideal"]) || 0; const realizado = parseFloat(m["Valor realizado"]) || 0; return ideal > 0 && (realizado / ideal) * 100 < LIMITE_ALERTA_META; }); if (comprometido >= LIMITE_ALERTA_COMPROMETIMENTO || metasComDesvio.length >= 2) return "CRÍTICO 🔴"; if (comprometido >= 65 || metasComDesvio.length === 1) return "ATENÇÃO 🟡"; return "SAUDÁVEL 🟢"; } // MONTAGEM DO ASSUNTO DO E-MAIL function montarAssunto(config, nivel) { const periodo = config["Mês/Ano"] || "este mês"; return `[${nivel}] Relatório de Metas Financeiras — ${periodo}`; } // MONTAGEM DO HTML DO E-MAIL function montarEmailHtml(config, analises, resumo, nivel) { const corNivel = nivel.includes("CRÍTICO") ? "#e74c3c" : nivel.includes("ATENÇÃO") ? "#f39c12" : "#27ae60"; return ` <div style="font-family: Arial, sans-serif; max-width: 620px; margin: auto; color: #333;"> <div style="background: ${corNivel}; padding: 20px; border-radius: 8px 8px 0 0;"> <h2 style="color: #fff; margin: 0;">📊 Relatório de Metas Financeiras</h2> <p style="color: #fff; margin: 6px 0 0;">${config["Mês/Ano"] || ""} — Status: <strong>${nivel}</strong></p> </div> <div style="background: #f9f9f9; padding: 20px; border: 1px solid #ddd;"> <h3 style="color: #555;">📌 Resumo do Mês</h3> <table style="width:100%; border-collapse: collapse; font-size: 14px;"> <tr><td style="padding:6px; border-bottom:1px solid #eee;">Total de Receitas</td> <td style="padding:6px; border-bottom:1px solid #eee; font-weight:bold;">R$ ${resumo["Total de Receitas"] || 0}</td></tr> <tr><td style="padding:6px; border-bottom:1px solid #eee;">Total de Despesas</td> <td style="padding:6px; border-bottom:1px solid #eee; font-weight:bold;">R$ ${resumo["Total de Despesas"] || 0}</td></tr> <tr><td style="padding:6px; border-bottom:1px solid #eee;">Saldo do Mês</td> <td style="padding:6px; border-bottom:1px solid #eee; font-weight:bold;">R$ ${resumo["Saldo do Mês"] || 0}</td></tr> <tr><td style="padding:6px;">% da Renda Comprometida</td> <td style="padding:6px; font-weight:bold;">${resumo["% da Renda Comprometida"] || 0}</td></tr> </table> <h3 style="color: #555; margin-top: 24px;">🤖 Análise da IA</h3> <h4 style="margin-bottom: 4px;">Resumo mensal</h4> <p style="font-size: 14px; line-height: 1.6;">${analises["Resumo mensal"] || "—"}</p> <h4 style="margin-bottom: 4px; color: ${corNivel};">⚠️ Alertas</h4> <p style="font-size: 14px; line-height: 1.6;">${analises["Alertas"] || "Nenhum alerta identificado."}</p> <h4 style="margin-bottom: 4px; color: #2980b9;">💡 Sugestões</h4> <p style="font-size: 14px; line-height: 1.6;">${analises["Sugestões"] || "—"}</p> </div> <div style="background: #eee; padding: 12px 20px; border-radius: 0 0 8px 8px; font-size: 12px; color: #888;"> Gerado automaticamente pela sua planilha de Metas Financeiras Inteligentes. </div> </div> `; } // TRIGGER MENSAL — ATIVA (todo dia 1º às 08h) function ativarTriggerMensal() { // Evita duplicação de triggers desativarTriggerMensal(); ScriptApp.newTrigger("enviarRelatorioAutomatico") .timeBased() .onMonthDay(1) .atHour(8) .create(); SpreadsheetApp.getUi().alert("✅ Envio automático ativado! Todo dia 1º às 08h você receberá o relatório."); } // TRIGGER MENSAL — DESATIVA function desativarTriggerMensal() { ScriptApp.getProjectTriggers() .filter(t => t.getHandlerFunction() === "enviarRelatorioAutomatico") .forEach(t => ScriptApp.deleteTrigger(t)); // Só mostra alerta se chamado diretamente pelo menu const ui = SpreadsheetApp.getUi(); try { ui.alert("🔕 Envio automático desativado."); } catch(e) {} }
Como o nível de alerta é calculado
- Se o % da renda comprometida ultrapassa 80%, o status vai para 🔴 Crítico
- Se duas ou mais metas mensais estão abaixo de 50% de cumprimento, também vai para 🔴 Crítico
- Valores intermediários resultam em 🟡 Atenção
- Tudo dentro do esperado resulta em 🟢 Saudável
O e-mail em HTML
Ativando o envio automático
Resultado esperado
- O status do mês em destaque no assunto, por exemplo: [SAUDÁVEL 🟢] Relatório de Metas Financeiras — Fevereiro/2026
- Tabela com os números do mês (receitas, despesas, saldo, % comprometido)
- Os três blocos de análise da IA em linguagem natural
- Rodapé identificando que foi gerado automaticamente pela planilha

Comentários