# Automatisch PDF-documenten genereren met Apps Script Automatisch PDF-documenten genereren met Apps Script bespaart enorm veel handwerk bij facturen, certificaten en rapporten. Je maakt een Google Docs-sjabloon met placeholders, vult die per ontvanger met data en exporteert het resultaat als PDF. In dit artikel leer je de complete flow: sjabloon kopieren, vullen, exporteren, opslaan en mailen. [[TOC]] ## De aanpak met een sjabloon De betrouwbaarste manier om PDF's te genereren is via een Google Docs-sjabloon. In dat sjabloon zet je placeholders zoals {{naam}} en {{bedrag}}. Per ontvanger maak je een kopie, vervang je de placeholders met echte waarden en exporteer je die kopie als PDF. Zo houd je opmaak en inhoud netjes gescheiden, en pas je het ontwerp aan zonder een regel code te wijzigen. :::info title="getAs en MimeType" Vrijwel elk Google-bestand kun je naar een ander formaat exporteren met `getAs(MimeType.PDF)`. Dat geeft een blob terug die je kunt opslaan, mailen of verder verwerken. In plaats van `MimeType.PDF` mag je ook de letterlijke string `'application/pdf'` gebruiken. De volledige lijst MimeType-waarden staat op developers.google.com/apps-script/reference/base/mime-type. ::: ## Het sjabloon kopieren en vullen Begin met een sjabloon-document waarvan je het id kent. Dat id staat in de URL van het Doc, tussen `/d/` en `/edit`. Maak een kopie, open die en vervang de placeholders: ```javascript function genereerPdf(naam, bedrag) { const sjabloonId = 'jouw-sjabloon-doc-id'; const kopie = DriveApp.getFileById(sjabloonId).makeCopy('Factuur ' + naam); const doc = DocumentApp.openById(kopie.getId()); const body = doc.getBody(); body.replaceText('{{naam}}', naam); body.replaceText('{{bedrag}}', bedrag); body.replaceText('{{datum}}', new Date().toLocaleDateString('nl-NL')); doc.saveAndClose(); return kopie; } ``` `saveAndClose()` is belangrijk: pas daarna zijn je wijzigingen vastgelegd en klaar voor export. Sla je dit over, dan exporteer je mogelijk nog de ongevulde versie. ## Exporteren naar PDF en opslaan Met de gevulde kopie maak je nu de PDF en sla je die op in een map: ```javascript function maakEnBewaarPdf(naam, bedrag) { const kopie = genereerPdf(naam, bedrag); const pdf = kopie.getAs(MimeType.PDF); const map = DriveApp.getFoldersByName('Facturen').next(); const pdfBestand = map.createFile(pdf).setName('Factuur ' + naam + '.pdf'); kopie.setTrashed(true); Logger.log('PDF opgeslagen: ' + pdfBestand.getUrl()); return pdfBestand; } ``` `kopie.setTrashed(true)` ruimt het tijdelijke Doc op zodat je Drive niet volloopt met kopieen. :::warn title="Ruim tijdelijke documenten op" Vergeet niet het tijdelijke Docs-bestand op te ruimen met `setTrashed(true)`. Genereer je honderden facturen zonder op te ruimen, dan blijven er honderden losse documenten staan die je Drive vervuilen en lastig terug te vinden maken. Alleen de PDF hoort te blijven. ::: ## De PDF direct mailen De flow wordt compleet als je de PDF meteen naar de juiste persoon mailt: ```javascript function stuurFactuur(naam, email, bedrag) { const pdfBestand = maakEnBewaarPdf(naam, bedrag); GmailApp.sendEmail(email, 'Je factuur', 'Beste ' + naam + ', in de bijlage vind je je factuur.', { attachments: [pdfBestand.getAs(MimeType.PDF)] }); } ``` ## In bulk vanuit een spreadsheet Het echte tijdwinst zit in bulkverwerking. Lees een lijst klanten uit Sheets en genereer per rij een PDF: ```javascript function bulkFacturen() { const blad = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Klanten'); const data = blad.getRange(2, 1, blad.getLastRow() - 1, 3).getValues(); data.forEach(function(rij) { const naam = rij[0]; const email = rij[1]; const bedrag = rij[2]; if (email) { stuurFactuur(naam, email, bedrag); } }); } ``` :::tip title="Test eerst met een enkele rij" Test je sjabloon eerst met een enkele rij voordat je de hele lijst verwerkt. Controleer of alle placeholders correct vervangen worden en de opmaak klopt. Een fout in het sjabloon vermenigvuldigt zich anders over honderden PDF's. ::: ## Let op quota en uitvoeringstijd Bij bulkverwerking loop je tegen de Apps Script-limieten aan. Een script-uitvoering mag maximaal zes minuten duren, en `GmailApp.sendEmail` heeft een dagelijks verzendquotum (doorgaans honderd e-mails per dag voor een gratis account en vijftienhonderd voor een Workspace-account). Verwerk grote lijsten daarom in batches en bewaar de voortgang. :::warn title="Kosten van veel documentbewerkingen" Elke `makeCopy`, `replaceText` en PDF-export telt mee voor de quota. Genereer je duizenden documenten in een keer, splits het werk dan op met een tijdgestuurde trigger die telkens een blok rijen afhandelt en de laatst verwerkte rij onthoudt via `PropertiesService`. ::: :::howto title="Een PDF-generatieflow opzetten" 1. Maak een Google Doc met placeholders zoals {{naam}} en {{bedrag}}. 2. Noteer het document-id uit de URL, tussen `/d/` en `/edit`. 3. Schrijf een functie die het sjabloon kopieert en de placeholders vervangt met `replaceText()`. 4. Roep `saveAndClose()` aan en exporteer de kopie met `getAs(MimeType.PDF)`. 5. Sla de PDF op met `createFile()` en ruim de tijdelijke kopie op met `setTrashed(true)`. 6. Mail de PDF eventueel direct naar de ontvanger met `GmailApp.sendEmail`. ::: :::faq ### Kan ik ook een spreadsheet naar PDF exporteren? Ja. Een hele spreadsheet of een specifiek blad exporteer je ook met `getAs(MimeType.PDF)`. Voor meer controle over het uitvoerformaat, zoals paginaformaat, marges of een specifiek bereik, gebruik je een export-URL met parameters via `UrlFetchApp`. ### Waarom is mijn PDF leeg of niet bijgewerkt? Waarschijnlijk heb je `saveAndClose()` vergeten. Pas na het opslaan en sluiten van het Doc staan je tekstvervangingen in de export. Controleer ook of je het juiste document-id gebruikt. ### Hoe vermijd ik dat mijn Drive volloopt? Gooi de tijdelijke Docs-kopie weg met `setTrashed(true)` zodra de PDF gemaakt is. Bewaar alleen de PDF in je map. ### Kan ik afbeeldingen in de PDF zetten? Ja. Plaats afbeeldingen in het Docs-sjabloon zelf, die komen mee in de export. Dynamische afbeeldingen voeg je per kopie toe met `body.appendImage()` of door een placeholder-afbeelding te vervangen. ### Waarom krijg ik een foutmelding over toestemming? Bij de eerste uitvoering vraagt Apps Script toestemming voor toegang tot Drive, Docs en Gmail. Doorloop het autorisatiescherm en geef akkoord. Krijg je daarna nog fouten, controleer dan of het script de juiste scopes heeft in het `appsscript.json`-manifest. ### Hoe verwerk ik duizenden facturen zonder timeout? Splits het werk op met een tijdgestuurde trigger die per uitvoering een blok rijen afhandelt. Bewaar de laatst verwerkte rij met `PropertiesService` zodat de volgende uitvoering verdergaat waar de vorige stopte. ::: ## Volgende stap Combineer PDF-generatie met een trigger voor automatische maandfacturen, zie [[apps-script-tijdgestuurde-trigger|tijdgestuurde triggers]], of sla de PDF's gestructureerd op, zie [[apps-script-drive-bestand|bestanden aanmaken in Drive]].