Aan de hand van template files en gegevens in een sheet, documenten genereren en versturen.
Deze files worden gegenereerd en bewaard op een "shared drive" of op een "my drive".
De functionaliteit is te vergelijken met Autocrat, alleen heb je hier de code volledig in de hand en is de verstuurde mail een html mail met extra mogelijkheden.
De mail wordt gestuurd als een html mail met een PDF attachment voor een extra document
Zo kan de header enkel bestaan uit één foto, zonder extra info.
In de documenten kan je linken gebruiken, deze worden gewoon over gehaald vanuit de template.
Je kan tabellen invoeren, waardoor gegevens in de tabel geformateerd worden (rapporten)
De header kan uitsluitend bestaan uit één foto, logobanner, andere velden worden niet ondersteund.
In de template file, een google doc, kan je gebruik maken van nagenoeg alle formattering die ook binnen Google docs kan gebruikt worden (behalve auto index, header footer etc)
De veldnamen woredn geencpsuleerd in dubbele tekens: <<fieldname>>.
Deze komt overeen met de kolom lable in de sheet, van waaruit je de data gaat halen.
Linken kunnen eenvoudig voorzien worden, door de tekst aan te duiden en er een link aan toe te kennen via het link symbool in google docs.
De normale formattering van tabellen kan gebruikt worden, waar je de velden kan invullen met variabele veldnamen.
Door de vertaling van Doc naar HTML lukt het niet goed om de formattering in orde te houden.
Vandaar dat het gebruik van figuren of fotomateriaal in het document wordt afgeraden.
Deze worden nl als bijlage meegestuurd, wat niet wenselijk is naar vormgeving.
De bronfile is een sheet, waarin de velden als kolommen worden gedefinieerd.
Tevens kan je de sheet gebruiken om de keuze van template en info file te bepalen en om een selectie te maken van de records die je wil behandeld zien.
Deze routine maakt een document aan met het email bericht van één user gebaseerd op een specifieke template file
De documenten die aangemaakt worden, vinden we terug onder de folder van de sheet met de naam van het station
call_recoveryEmail_log
De gekozen template file vinden we terug in de sheet
In de template file worden de velden gekenmerkt door <<text>>.
Enkel de records waarin de Update kolom de waarde "U" bevat worden gebruikt, zodat jezelf kan bepalen wat gemaakt/verstuurd wordt.
Er zijn verschillende profielen waardoor er ook verschillende template files zijn:
Delete, New, Primary email changed(callsign changed) en Privacy(ter kennisgeving)
De template files mogen enkel één foto, pagina breedt als header file bevatten.
Figuren in de tekst worden als bijlage gestuurd.
De ID van de file die als email content gaat dienst doen, wordt in de sheet ingevuld in het veld email_content
Het Update veld wordt aangepast naar "generated" zodat de EmailSend enkel deze zal versturen die gegenereerd zijn.
Het copieren van de templatefile naar een nieuwe naam gebeurt door de functie:
let log_doc = CopyTemplate1(Emails.EmailTemplate[r], copyname)
Stap1: Vermits het doelbestand een copie is van de template file maar met een nieuwe unieke naam, plaatsten we deze in dezelfde folder.
We zoeken de info van de file (id + parentfolderid) op.
var fileinfo = fileInfo(templatename) (zie drive applicatie)
Stap2: Indien de file gevonden wordt binnen de aangegeven folder, wordt deze gewist.
Blijkbaar werkt hier de driveapp wel op de shared drive voor het vinden van een file met een specifieke naam, waarschijnlijk omdat expliciet de parent folder wordt meegegeven.
Stap3: Maak een copy van de bestaande template file.
Deze copy wordt steeds gemaakt op je My drive root.
Stap 4: Verplaats de gecopieerde file naar de folder waarin ook de template zit.
Dit doe je door de file toe te voegen aan de destination folder
Stap 5: Verwijder hierna de file uit de rootfolder.
function CopyTemplate1(templatename, copyname) {
//STAP1: zoek de folder van de template file
var fileinfo = fileInfo(templatename)
var dest_dir = fileinfo.parentid
var templateID= fileinfo.id
var dest_folder = DriveApp.getFolderById(dest_dir);
//STAP2: wis het doelbestand copyname, als deze al bestaat
let file_found = DriveApp.getFolderById(dest_dir).getFilesByName(copyname);
while (file_found.hasNext()) {
file_found.next().setTrashed(true);
Logger.log(`Wis log file van ${copyname}`)
}
//STAP3: maak copybestand opnieuw aan, standaard is dit in de root folder van een gebruiker
let copyID = DriveApp.getFileById(templateID).makeCopy(copyname).getId()
//STAP4: verplaats copybestand naar de folder van de template file
var SourceParents = DriveApp.getFolderById(copyID).getParents();
while (SourceParents.hasNext())
var source_dir = SourceParents.next().getId();
var source_folder = DriveApp.getRootFolder();
var file = DriveApp.getFileById(copyID);
dest_folder.addFile(file);
// STAP5: verwijder de file uit de root folder.
source_folder.removeFile(file);
Logger.log(`Create log file van ${copyname}`)
return copyID
}
De copie is nog steeds een Gdoc, waardoor je de verschillende onderdelen appart kan benaderen als Header, Section en Footer,
De headers array, is de eerste lijn van de sheet (kolomheaders) en de veldnamen worden gevormd dmv: <<${headers[i]}>>
De waarde van een veld vinden we terug met:
let colVal = Emails[headers[i]][r
Dmve de replaceText method van een document, kan je in de 3 onderdelen teksten die verwijzen naar het voorgaande vervangen.
Het document moet je afsluiten, dmv: copyDoc.saveAndClose()
De ID van de file alsook de status van omvormen wordt terug in de sheet gezet, ter controle en verdere verwerking mbv de functie EmailSend()
var copyDoc = DocumentApp.openById(log_doc);
// Get the document’s body section
var copyHeader = copyDoc.getHeader();
var copyBody = copyDoc.getActiveSection();
var copyFooter = copyDoc.getFooter();
for (let i = 0; i < headers.length; i++) {
let normalizedFieldName = `<<${headers[i]}>>`;
let colVal = Emails[headers[i]][r];
if (copyHeader) {
copyHeader.replaceText(normalizedFieldName, colVal);
}
if (copyBody) {
copyBody.replaceText(normalizedFieldName, colVal);
}
if (copyFooter) {
copyFooter.replaceText(normalizedFieldName, colVal);
}
}
// Save and close the temporary document
copyDoc.saveAndClose();
Verstuurt mails vanuit de sheet, door gebruik te maken van de cellen binnen de sheet.
De mails die verstuurd worden kijgen als body de inhoud van het document gegenereerd in EmailGen() in HTML vorm
Als attachment wordt er tevens de file EmailInfo als PDF aan toegevoegd.
Het To adres wordt bepaald aan de hand van de instellingen: testrun of niet.
bij testrun, wordt het test_email adres gebruikt
anders wordt het RecoveryEmail van de gebruiker, zo komen de mails toe op hun priveadres
Het reply_to adres kan een generiek adres zijn of een specifiek adres, dat je dient in te stellen via Configuration/Define run parameters
De mail wordt eveneens als CC naar het myuba adres van de gebruiker gestuurd.
De titel van de mail is "MYUBA.BE domain info for <call>, <voornaam> <naam>" en wordt verstuurd door één van de myuba-sysops.*
function EmailSend() {
//Lock access to vars/sheet from triggers
LockService.getScriptLock().waitLock(300000) //max 6min
//globalvar voor definities en testruns
var testrun = PropertiesService.getScriptProperties().getProperty('testrun');
var ReplyTo_email_box = PropertiesService.getScriptProperties().getProperty('ReplyTo_mailadx');
var Test_Email_adx = PropertiesService.getScriptProperties().getProperty('test_email');
// Convert Emails sheet to object
let Emails = TableToObject("Emails")
var ss = SpreadsheetApp.getActiveSpreadsheet()
//get field names
var values = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Emails").getDataRange().getValues();
// Extract headers
var headers = values[0];
for (r = 0; r < Emails.Call.length; r++) {
// Als het update veld = U, dan maak een document aan met de ingevulde velden en met de naam van de callsign_sendmail.
if (Emails.Update[r] == "generated") {
let EmailAddress = Emails.RecoveryEmail[r]
let Myuba_adx = Emails.EmailAddress[r]//myuba email adres
if (EmailAddress != "") {
let subject = `MYUBA.BE domain info for ${Emails.Call[r]}, ${Emails.First_Name[r]} ${Emails.Last_Name[r]}`
let docID = Emails.email_content[r]
// get file by name from shared drive and attach as PDF
let message = ''
var file_info = DriveApp.getFileById(fileInfo(Emails.EmailInfo[r]).id)
var attachment_doc = file_info.getAs(MimeType.PDF)
if (testrun == 1) {
SendDocAsHTML(docID, Test_Email_adx, subject, attachment_doc, ReplyTo_email_box, "")
} else {
SendDocAsHTML(docID, EmailAddress, subject, attachment_doc, ReplyTo_email_box, Myuba_adx)
}
// Clear Email veld
Emails.email_content[r] = ""
// Clear Update status
Emails.Update[r] = ""
Emails.Uitgevoerd[r] = new Date().toISOString()
Logger.log("Email send " + EmailAddress + " " + testrun);
}
}
}
// Update sheet
ObjectToTable(Emails, "Emails");
LockService.getScriptLock().releaseLock()}
Het is mogelijk om een document te openen als een PDF type met de method getAs().
Deze wordt gebruikt voor het maken van de attachment file: attachment_doc.
Het als PDF doorsturen van een bijlage, zorgt ervoor dat ook niet-google gebruikers de extra gegevens kunnen lezen, maar zo behoud jij de mogelijkheid om toch de G-suite te gebruiken voor het maken van alle documenten.
var file_info = DriveApp.getFileById(fileInfo(Emails.EmailInfo[r]).id)
var attachment_doc = file_info.getAs(MimeType.PDF)
zie ook Gmail
Er is geen GAS functie die je toe laat om een Gdoc om te vormen naar een html versie, die direct bruikbaar is in een email body.
Deze functie wordt gebruikt voor het versturen als HTML van het document, samen met een attachment in PDF.
Specifieke gegevens, zoals het reply_to adx, het subject alsook een tweede bestemmeling (Myuba_adx) worden aan deze functie meegegeven.
SendDocAsHTML(docID, EmailAddress, subject, attachment_doc, ReplyTo_email_box, Myuba_adx)
Bij de eerste run, zal je gevraagd worden om toestemming te verlenen (OAuth concent), doordat je toegang wil naar je email en drive stuk.
Stap 1: get HTML versie document
Het bekomen van een HTML versie van een bestaan document kan dmv een functie die ingebakken zit in de REST api voor gdocs, het export formaat:
&exportFormat=html
Om dit mogelijk te maken moet je de OAuth lib aanroepen vanuit je script en de nodige credentials meegeven met je URL fetch:
var html = UrlFetchApp.fetch(url, param).getContentText();
De parameters bepalen wat er dient te gebeuren (get) en welke opties er dienen meemgegeven te worden)
var param = {
method: "get",
headers: {
"Authorization": "Bearer " + ScriptApp.getOAuthToken()
},
muteHttpExceptions: true,
};
De muteHTTPExeptions, maken het document meer "universeel".
var html = UrlFetchApp.fetch(url, param).getContentText()
Stap 2: convert to email
De verkregen html code dient verder omgevormd te worden naar het formaat van een email, door het toevoegen van een aantal velden.
We maken hiervan een raw document met een fictief to address in, wat nadien door de GmailApp wordt vervangen bij het versturen.
Ook hier gebruiken we de base64EncodeWebSafe optie, zodat het universeel blijft en gekoppeld is aan het charset UTF-8.
var raw = Utilities.base64EncodeWebSafe("Subject: Test\r\n" +
"From: " + Session.getActiveUser().getEmail() + "\r\n" +
"To: test@gmail.com\r\n" +
"Content-Type: text/html; charset=UTF-8\r\n\r\n" +
html + "\r\n\r\n");
Door een nieuw bericht aan te maken en de raw data te koppelen aan dit bericht, is het formaat verzekerd.
var message = Gmail.newMessage();
message.raw = raw;
Stap 3: verstuur mail met attachment
Uiteindelijk wordt de mail verstuurd met de GmailApp:
GmailApp.sendEmail(toEmail, subject, message, { htmlBody: html, attachments: attachment_doc, name: 'Myuba-sysop', replyTo: reply_to, cc: cc });
/**
* Send a google doc als email, simulating the copy-paste of a google document to a gmail body.
* Based on: https://stackoverflow.com/questions/43134746/google-app-script-how-to-get-text-with-formatting-from-docs-and-use-it-for-body
*
* @param {string} id, id of google document, used as body of email
* @param {string} toEmail, email addres of destination
* @param {string} subject, subject of email
* @param {blob} attachment_doc, google document that will be attached to the email
* @param {string} reply_to, email address replacing the default reply to address
* @param {string} cc, email address of CC
*/
function SendDocAsHTML(id, toEmail, subject, attachment_doc, reply_to, cc) {
var url = "https://docs.google.com/feeds/download/documents/export/Export?id=" + id + "&exportFormat=html";
var param = {
method: "get",
headers: {
"Authorization": "Bearer " + ScriptApp.getOAuthToken()
},
muteHttpExceptions: true,
};
var html = UrlFetchApp.fetch(url, param).getContentText();
var raw = Utilities.base64EncodeWebSafe("Subject: Test\r\n" +
"From: " + Session.getActiveUser().getEmail() + "\r\n" +
"To: test@gmail.com\r\n" +
"Content-Type: text/html; charset=UTF-8\r\n\r\n" +
html + "\r\n\r\n");
var message = Gmail.newMessage();
message.raw = raw;
GmailApp.sendEmail(toEmail, subject, message, { htmlBody: html, attachments: attachment_doc, name: 'Myuba-sysop', replyTo: reply_to, cc: cc });
}