# Een dagelijks e-mailrapport automatiseren met Apps Script Een dagelijks e-mailrapport automatiseren met Apps Script is het perfecte project om alle basistechnieken samen te brengen. Je leest data, vat die samen, giet het in een nette mail en laat een trigger het elke ochtend versturen, helemaal zonder dat je erbij bent. In dit artikel bouw je zo'n rapport stap voor stap op. [[TOC]] ## Het idee achter de automatisering Het doel is een mail die elke werkdag om 07:00 in je inbox ligt met de belangrijkste cijfers van gisteren. De bouwstenen zijn: data lezen uit een spreadsheet, die data samenvatten, een leesbare HTML-mail bouwen en een tijdgestuurde trigger die het geheel start. Elk onderdeel ken je misschien al, hier knoop je ze aan elkaar. :::info title="Bouwstenen herzien" Dit project combineert **SpreadsheetApp** (data lezen), **GmailApp** (e-mails versturen) en een **time-driven trigger** (tijdgestuurd starten). De referentie van elke service vind je op `developers.google.com/apps-script/reference`. ::: In het kort doorloopt het script vier vaste fases: | Fase | Wat er gebeurt | Belangrijkste methode | | --- | --- | --- | | Lezen | Haal de orderdata uit de spreadsheet | `getRange().getValues()` | | Samenvatten | Bereken aantal en totaal van afgeronde orders | eigen logica | | Mailen | Bouw HTML en verstuur de mail | `GmailApp.sendEmail()` | | Plannen | Laat een dagelijkse trigger het om 07:00 starten | `ScriptApp.newTrigger()` | ## Stap 1: de data lezen en samenvatten Stel je hebt een blad met verkooporders, met per rij een datum, een bedrag en een status. Je leest de data en berekent de totalen: ```javascript function maakSamenvatting() { const blad = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Orders'); const data = blad.getRange(2, 1, blad.getLastRow() - 1, 3).getValues(); let totaal = 0; let aantal = 0; data.forEach(function(rij) { const bedrag = rij[1]; const status = rij[2]; if (status === 'afgerond') { totaal += bedrag; aantal++; } }); return { aantal: aantal, totaal: totaal }; } ``` Let op de aanroep `getLastRow() - 1`: die zorgt dat je alleen de rijen met data leest en niet de kopregel. Staat er nog geen enkele orderregel, dan kan `getLastRow()` gelijk zijn aan de kopregel, vang dat in de volgende stappen af. ## Stap 2: een nette HTML-mail bouwen Een platte tekstmail leest niemand graag. Bouw een eenvoudige HTML-tabel zodat de cijfers eruit springen: ```javascript function bouwHtml(samenvatting) { return '
| Afgeronde orders | ' + samenvatting.aantal + ' |
|---|---|
| Totaalbedrag | EUR ' + samenvatting.totaal.toFixed(2) + ' |
Gegenereerd op ' + new Date().toLocaleString('nl-NL') + '
'; } ``` :::tip title="Houd de HTML simpel" Gebruik inline stijlen en een gewone tabel. Mailprogramma's ondersteunen lang niet alle moderne CSS, en een nette tabel met inline opmaak wordt overal goed weergegeven, ook in Gmail, Outlook en op mobiel. ::: ## Stap 3: het rapport versturen Nu koppel je de samenvatting en de HTML aan een verzendfunctie: ```javascript function stuurDagrapport() { const samenvatting = maakSamenvatting(); const html = bouwHtml(samenvatting); const ontvanger = 'team@cloud-captains.com'; GmailApp.sendEmail(ontvanger, 'Dagrapport ' + new Date().toLocaleDateString('nl-NL'), 'Bekijk dit rapport in een HTML-client.', { htmlBody: html, name: 'Rapportage Bot' }); } ``` De derde parameter is de platte-tekstversie, een terugval voor clients die geen HTML tonen. De opties `htmlBody` en `name` regelen de opgemaakte versie en de afzendernaam. ## Stap 4: de trigger instellen Tot slot zorg je dat het elke ochtend draait. Stel een dagelijkse trigger in en ruim eerst oude triggers op, zodat je niet per ongeluk twee mails per dag krijgt: ```javascript function installeerTrigger() { ScriptApp.getProjectTriggers().forEach(function(t) { if (t.getHandlerFunction() === 'stuurDagrapport') ScriptApp.deleteTrigger(t); }); ScriptApp.newTrigger('stuurDagrapport') .timeBased().everyDays(1).atHour(7).create(); } ``` Een tijdgestuurde trigger draait in het tijdvenster dat je met `atHour()` opgeeft, dus rond 07:00, niet op de seconde nauwkeurig. Dat is voor een ochtendrapport prima. :::warn title="Test eerst handmatig" Voer `stuurDagrapport` eerst met de hand uit voordat je hem op een trigger zet. Een fout in de samenvatting of de mail zou anders dagelijks stilletjes falen in een onbemande run, en dat merk je pas als iemand vraagt waar het rapport blijft. Controleer ook het uitvoeringslogboek na de eerste echte trigger-run. ::: ## De volledige flow in één oogopslag 1. **Lezen**: haal de orderdata uit de spreadsheet met `getValues()`. 2. **Samenvatten**: bereken aantal en totaal van de afgeronde orders. 3. **Mailen**: bouw de HTML en verstuur met `GmailApp.sendEmail()`. 4. **Plannen**: laat een dagelijkse trigger het script om 07:00 starten. :::faq ### Hoe stuur ik het rapport naar meerdere mensen? Geef meerdere adressen komma-gescheiden mee als ontvanger, of zet de ontvangers in een spreadsheet en loop eroverheen. ### Kan ik een grafiek meesturen? Ja. Maak een grafiek in Sheets, haal die op met `getCharts()` en voeg hem als inline-afbeelding toe via het `inlineImages`-veld van `sendEmail`. ### Wat als er geen data is? Vang dat af: stuur een mail met de melding dat er geen orders waren, of sla het versturen die dag over. Zo weet de ontvanger dat het script wel draaide. ### Hoe verander ik het tijdstip? Pas `atHour(7)` aan naar het gewenste uur en draai `installeerTrigger` opnieuw, zodat de oude trigger wordt vervangen. ### Waarom mailt het script niet op het exacte uur? Tijdgestuurde triggers draaien binnen een tijdvenster van ongeveer een uur rond het opgegeven uur, niet op de minuut precies. Voor een ochtendrapport is dat geen probleem. ### Loop ik tegen verzendlimieten aan? Gmail kent dagelijkse verzendlimieten per account. Voor één rapport per dag zit je daar ruim onder, maar als je naar veel losse ontvangers mailt, houd je de quota in de gaten via het uitvoeringslogboek. ::: ## Volgende stap Dit project laat zien hoe sterk Apps Script wordt als je services combineert. Bouw verder met [[apps-script-rapportage-uitbreiden|complexere rapportages]] of zet een [[apps-script-approval-flow|goedkeuringsflow]] op met dezelfde technieken.