Google Docs: sending email with variable content from the spreadsheet - google-apps-script

i want to send emails that contains text and variable values from the spreadsheet.
For that i ran the sendemails-script which works well. But at the example the cell that was declared as "var message" didnt contain variable values but only text.
Is it possible to add "references to values" to this text?
Something like:
Hello,
last week you bought (value of B3) apples and (value of B4) cherries.
I think in Excel you can split text and formular units in one row, is there something like that in GoogleDocs?
Thanks for your help in Advance, i hope you could understand what i mean :)
Marten

Amit's suggestion is a good idea although it might be a bit complex if you want to keep the whole thing simple and/or adapt it to your needs... It's never easy to analyse a script that is the result of a lot of work... from someone else.
So I wrote a very simple script that does exactly what you ask, nothing more (and nothing less I hope)
It uses 3 columns and the base message has 3 placeholders but you can of course expand it the way you want.
It will be easy to customize it to your use case. I added many log in the code so you see exactly what is going on.
function simpleMerge(){
var sh = SpreadsheetApp.getActiveSheet();
var data = sh.getDataRange().getValues();
var headers = data.shift();
for(var n=0 ; n<data.length ; n++){
var baseMessage = "Hello #0#, \n\nlast week you bought #1# apples and #2# cherries.";
for(var c=0 ; c<data[n].length ; c++){
var placeHolder = '#'+c+'#';
var value = data[n][c];
Logger.log('replacing '+placeHolder+' with '+value);
baseMessage = baseMessage.replace(placeHolder,value);
}
Logger.log('message '+n+' = '+baseMessage);
//send message to who you want
}
}

Install the ultradox or mailchimp add-on or many others that do this with more flexibility.

Related

I don't manage to parse JSON in google app script

I'm trying to grab song lyrics from the orion.apiseeds lyrics API - it works and I get a JSON, that I'm incapable of parsing.
https://orion.apiseeds.com/api/music/lyric/Oasis/Wonderwall?apikey=xx
gives back
{"result":{"artist":{"name":"Oasis"},"track":{"name":"Wonderwall","text":"Today is gonna be the day that they're gonna throw it back to you.\r\nBy now you should've somehow realized what you gotta do.\r\nI don't believe that anybody, feels the way I do, about you now.\r\n\r\nBackbeat, the word is on the street that the fire in your heart is out.\r\nI'm sure you've heard it all before but you never really had a doubt.\r\nI don't believe that anybody, feels the way I do, about you now.\r\n\r\nAnd all the roads we have to walk are winding.\r\nAnd all the lights that lead us there are blinding.\r\nThere are many things that I, would like to say to you but I don't know how.\r\n\r\nBecause maybe, you're gonna be the one that saves me?\r\nAnd after all, you're my wonderwall.\r\n\r\nToday was gonna be the day but they'll never throw it back to you.\r\nBy now you should've somehow realized what you're not to do.\r\nI don't believe that anybody, feels the way I do, about you now.\r\n\r\nAnd all the roads that lead you there were winding.\r\nAnd all the lights that light the way are blinding.\r\nThere are many things that I, would like to say to you but I don't know how.\r\n\r\nI said maybe, you're gonna be the one that saves me?\r\nAnd after all, you're my wonderwall.\r\n\r\nI said maybe, (I said maybe)\r\nYou're gonna be the one that saves me?\r\nAnd after all, you're my wonderwall.\r\n\r\nI said maybe, (I said maybe)\r\nYou're gonna be the one that saves me? (that saves me)\r\nYou're gonna be the one that saves me? (that saves me)\r\nYou're gonna be the one that saves me? (that saves me)","lang":{"code":"en","name":"English"}},"copyright":{"notice":"Wonderwall lyrics are property and copyright of their owners. Commercial use is not allowed.","artist":"Copyright Oasis","text":"All lyrics provided for educational purposes and personal use only."},"probability":100,"similarity":1}}
My code to fetch this is:
function getLyrics(url) {
var response = UrlFetchApp.fetch(url);
var responseObject = JSON.parse(response.getContentText());
}
Then, that's where the problem arises.
1)
Logger.log(reponseObject); ==> gives the thing I pasted above.
2)
for (var i=0;i<responseObject.length;i++) {
var item = responseObject[i];
Logger.log(JSON.stringify(item));
==> gives NOTHING in the console...
3)
function printJson(myObject) {
// define an array of all the object keys
var headerRow = Object.keys(myObject);
// define an array of all the object values
var row = headerRow.map(function(key){ return myObject[key]});
// define the contents of the range
var contents = [
headerRow,
row
];
// select the range and set its values
var ss = SpreadsheetApp.getActive();
var rng = ss.getActiveSheet().getRange(1, 1, contents.length, headerRow.length )
rng.setValues(contents)
}
===> fills one row with "result" and the next row with all the rest of the JSON.
I feel like i'm missing a basic JSON-related thing...
Thanks for your help
var responseObject = JSON.parse(response.getContentText());
var lyrics = responseObject.result.track.text;
That was easy enough ;-)

Formatting in replaceText()

I've got doc.getBody().replaceText(oldregex,newstring) working fine in a Google Document script at the minute, and was hoping to set some bold/italic on newstring. This looks harder than I thought it would be. Has anyone found a tidy way to do this?
I'm currently thinking I'll need to...
Build newtext as a range with rangeBuilder
Find oldtext and select it as a range (somehow...)
Clear the oldtext range and insert the newtext range at the find location
This seems like a lot of work for something that would be trivial with HTML-like tags. I'm definitely missing something. Would really appreciate any suggestions.
Since replaceText only changes the plain text content, leaving formatting in place, the goal can be achieved by applying formatting before the replacement. First, findText goes through the text and sets bold to every match; then replaceText performs the replacement.
There are two cases to consider: only a part of text in an element is matched (which is typical) and entire element is matched. The property isPartial of RangeElement class distinguishes between these.
function replaceWithBold(pattern, newString) {
var body = DocumentApp.getActiveDocument().getBody();
var found = body.findText(pattern);
while (found) {
var elem = found.getElement();
if (found.isPartial()) {
var start = found.getStartOffset();
var end = found.getEndOffsetInclusive();
elem.setBold(start, end, true);
}
else {
elem.setBold(true);
}
found = body.findText(pattern, newString);
}
body.replaceText(pattern, newString);
}
This seems like a lot of work for something that would be trivial
This is both correct and typical for working with Google Documents using Apps Script.

Scanning range and paste copied information if a certain cell is empty

i'm still a beginner in this, so I might ask a lot of stupid questions.
My problem is the following:
I wrote this script:
function ThisTry() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var Ssheet = sheet.getSheetByName("Recap");
var nSheet = sheet.getSheetByName("Aktuell");
var rang1 = sheet.getRange("Aktuell!A1:Q28");
var colum = 1;
var columEnd = 20;
var ro = 85;
var roEnd = 112;
var clean = nSheet.getRange(29, 20);
var ad = clean.getValue();
if (ad == "", ro+=28, false);
if (ad == "", roEnd+=28, false);
var past = rang1.copyValuesToRange(Ssheet, colum, columEnd, ro, roEnd);
}
What I am doing is I copy some information from one sheet and paste it in another. But i want to create a code that watches if a certain cell is empty or not and if it is not I want to change the values of the variables that I use to define the range in copyValuesToRange in the code above.
This code currently works but it doesn't save the new values of the variables, so it does what it should the first time but after that it doesn't change the range
I know that my if statements are wrong but I have no idea how to fix them so that the code works.
Any suggestions? Thanks!
If someone is editing the contents of clean' you can check the value after an onEdit trigger event to see if the current value is different from the past value. You can maintain state between function calls by storing information in PropertiesService. I also like just storing stuff in files as ascii text because you can store so much stuff all in one place and if need be you can edit it with something like Drive Notepad. If your interested in that then spend some time learning about Drive.
If you wish to poll that value, then you could run code from a sidebar or dialog using Javascript timer functions and you can call any server side with google.script.run. In addition, that's a way to build sort of a control panel to watch the process from.
I don't know exactly what your trying to accomplish but I hope that I've given you some useful things to consider.

Formatting rows (color, line-through etc.) based on date in Google Sheets with script

I've made a list of events in Google Sheets to help me and my band to get an overview of when we are to play. We have had a lot of jobs lately, and it is getting a little hard to quickly figure out where the next job is...
If it's possible, I would like to automatically make the rows containing previous jobs in italics, line-through and the font-color gray if the dates i column C is before the today/current date.
I have been searching a lot for it, but haven't really quite found the right piece of code..
My skills in scripting is OK, but this is the first time for me to use Google apps script, so I would appreciate if you could explain some of the harder steps about the more Google Sheets specific parts of the code :)
Thanks a lot!
You don't need a script to do that : in your spreadsheet, format>conditional formating.
EDIT :
Since you seem to prefer using a script to customize it more personally (which I understand ;-)
here is a script to begin with : (it does not need a lot of explanations, see comments in code)
function formatOnDate() {
var sh = SpreadsheetApp.getActive().getActiveSheet();
var range = sh.getDataRange();
var data = range.getValues();
var color = '#CCC';// value you want
var style = 'italic';// value you want
var line = 'line-through';// value you want
var fontColors = range.getFontColors();// get all font colors
var fontLines = range.getFontLines();// lines
var fontStyles = range.getFontStyles();//style
//var today = new Date();// include today in sheet
var today = new Date(new Date().setDate(new Date().getDate()-1));// exclude today... uncomment the one you use
for(var n=1 ; n<data.length ; n++){ // start on row 2 so that headers are not changed
if(data[n][2] < today){
for(var c in data[0]){
fontColors[n][c]=color;//set format
fontLines[n][c]=line;//set format
fontStyles[n][c]=style;//set format
}
}
}
sh.getRange(1,1,data.length,data[0].length).clear();
// now update sheet with new data and style
sh.getRange(1,1,data.length,data[0].length).setValues(data).setFontColors(fontColors).setFontLines(fontLines).setFontStyles(fontStyles);
}
Test sheet here

How to Split Form entries and replace text within a cell

I have a form that serves as an application to receive volunteer teams for my NGO. What I want to do is create a script that sends an email to the registrar upon someone completing the form. That's the easy part which I know how to do.
I want to include in that "email notification" a few key answers from some questions for the registrar to see. This I also know how to accomplish.
here is my current code that works:
function Team_ApplicationMailer(e) {
var recipient = "myemail#gmail.com";
var timestamp = e.values[0];
var name = e.values[3];
var country = e.values[1]
var subject = e.values[1]+' wants to Volunteer!' ;
var startdate = e.values[12];
var enddate = e.values[13]
var hyperlink = "mylink.com"
htmlBody = '<u><strong>'+name+'</u></strong> from: <u><strong>'+country+'</strong></u>just completed the Teams Application Form for these dates: <u><strong>'+startdate+' to '+enddate+'</u></strong><br><br>Form completed on: <u><strong>'+timestamp+'</u></strong><br><br>View the Form: Click Here';
MailApp.sendEmail(recipient, subject, htmlBody, {htmlBody:htmlBody});
}
Here's the tricky part I want to add: I want to also add data found in e.values[19] and e.values[20], but these values are from either a multiple choice (e.values[19]) or checkbox (e.values[20]) and I need the values both simplified—i.e. some text deleted—and possibly split when emailed.
The two questions are basically identical. e.values[19] is "What do you want to do: 1st Priority" with some multiple-choice options. and e.values[20] is "What else do you want to do" with some checkbox options. Both questions have the same 7 choices and each choice has a long description (hence the need to shorten)
Basically I want e.values[19] which value looks like this:
optionX: (Long Description)
to look like this in the email:
What do you want to do: optionX.
I don't want the long description of the option in the "()" to be included.
For e.values[20] I want the values to look like this in the email:
What else do you want to do: optionA, optionB, optionC
INSTEAD of This:
optionA: (Long Description),optionB: (Long Description),optionC: (Long Description)
I've looked into the .replace and .split functions but don't know how to make them work together, especially for the checkbox option.
Thanks for the help!
I wrote a function for this. It just removes anything inside parentheses (). This seems to be what you're looking for.
var s = e.values[19];
s = s.replace(/\([^)]*\)/g,"");
If you have parentheses inside parentheses, let me know, and I will have to make a quick edit.
So what's happening here.
It's looking for a (.
It's looking for as many characters as it can while matching a ) at the end. This is without having a ) inside.
If you had allowed a ) inside, it would match optionA:(...), optionB: (...), optionC: (...). We want to avoid this, so we do not allow ) inside. That's what [^)] means.
The g flag means to match "globally", or everywhere in the string.