How to send email from a spreadsheet - google-apps-script

I have a spreadsheet on Google Docs with tasks for a job that we are working on at work. What I am wanting it to do is to send the whole row to the intended recipient but I can only get it to send the info from the first column after the email address. Everything has a due date on it and I would like to get it to send a reminder when it gets close to that date but I do not know how to do that.
Any help would be greatly appreciated.
Here is the code I have right now:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 3; // First row of data to process
var numRows = 2; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 2)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[0]; // First column
var message = row[1]; // Column B, Column C, Column D, Column E, Column F, Column G
var subject = "Email Test Spreadsheet";
MailApp.sendEmail(emailAddress, subject, message);
}
}

when you define your dataRange like this :
var dataRange = sheet.getRange(startRow, 1, numRows, 2)
you read data from startRow column 1 for numRows but only 2 columns (the last value is 'width') so you could easily modify your script to get all the columns you want just by changing this last value. Then using row[i].toString(), you will get your comma separated fields.
Then you might want to get a better presentation using HTML format to present data in a table for example but this is outside the point of your question ;-)

When you define a data range like this
var dataRange = sheet.getRange(startRow, 1, numRows, 2);
you are taking the data from A3:C5
you can also refer to the documentation
If you can post a sample spreadsheet as per the description of your problem, then it will be helpful for others to help you.

This piece: var message = row[1]; will only ever get the second element (index 1) in the array. You'll need to iterate through the row to get all the array elements.
var message = row[1];
message.concat(row[2]);
message.concat(row[3]);
And so on. Or you could build a loop.
http://www.w3schools.com/jsref/jsref_concat_string.asp
And to get the range, why do it the hard way? sheet.getRange("A2:B3");
That's the range you said you're trying to get in the comment above that line, although it is only 4 cells. sheet.getRange("A2:G3") would get two rows out to column G.
Of course, if you add rows to the sheet, you'd have to modify the code every time.
Instead, try this.
var bottomRow = sheet.getLastRow();
var rangeInA1 = "A2:G"+bottomRow;
var dataRange = sheet.getRange(rangeInA1);

Related

Google Appscript: Copy Data from a Form Sheet to Another Sheet in Last Row and Clear Form

Trying to get an Appscript to run but I can't seem to figure out the last few steps.
Background: I have a Google Sheet with two tabs, #1 is called "Data Form" which hosts a fillable form to capture Transaction information to then be input onto tab #2 called "Posted Transactions". This is a personal budget spreadsheet..
Anyways, The script below is intended to take the information input on the "Data Form", verify what the last row with data is on the "Posted Transactions" tab based on whether or not Column A has any data. (To further clarify, the "Posted Transactions" tab has formulas in columns G-I which prohibits me from using a simple "Find last Row" script.)
As it is written now, I receive an error "Exception: The number of columns in the data does not match the number of columns in the range. The data has 6 but the range has 1.
RecordNewTransaction # Code.gs:24"
Any suggestions to make this work properly?
UPDATE:
var dataRange = datasheet.getRange(lastRow+1,1,1,datasheet.getLastColumn()-3);
After many attempts at trial and error, I needed to edit the line shown above. Current & full script is performing as expected now and is shown below. Image snips of what I was trying to accomplish are also shown for reference.
function RecordNewTransaction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSS = ss.getSheetByName("Data Form"); //Form Sheet
var datasheet = ss.getSheetByName("Posted Transactions"); //Data
//Input Values
var values = [[formSS.getRange("B4").getValue(),
formSS.getRange("B6").getValue(),
formSS.getRange("B8").getValue(),
formSS.getRange("B10").getValue(),
formSS.getRange("B12").getValue(),
formSS.getRange("B14").getValue()]];
var columnToCheck = datasheet.getRange("A:A").getValues();
var lastRow = getLastRowSpecial(columnToCheck);
Logger.log(lastRow);
var dataRange = datasheet.getRange(lastRow+1,1,1,datasheet.getLastColumn()-3);
Logger.log(dataRange);
var dataValues = dataRange.getValues();
Logger.log(dataValues);
dataRange.setValues(values);
Logger.log(dataRange.setValues(values))
formSS.getRange('B4:B14').clearContent();
};
function getLastRowSpecial(range){
var rowNum = 0;
var blank = false;
for(var row = 0; row < range.length; row++){
if(range[row][0] === "" && !blank){
rowNum = row;
blank = true;
}else if(range[row][0] !== ""){
blank = false;
};
};
return rowNum;
};
Try
var dataRange = datasheet.getRange(lastRow,1,values.length,values[0].length)
replace 1 as necessary (this is the firts column where the data will be stored
Reference:
getRange(row, column, numRows, numColumns)
See edited question above which contains the revised script needed.
The problem here was that columns G-I of my results sheet contain formulas (shown in grey) which required this line below to be modified to grab the last column -3, otherwise the script was looking at too many columns that it didn't need to. Also had to modify "lastRow" to "lastRow+1" because this kept overriding the very last line of data I already had input and the +1 will make new data go to the next available row.
var dataRange = datasheet.getRange(lastRow+1,1,1,datasheet.getLastColumn()-3);

How to copy cell value to another sheet base on criteria (Apps Script)

I'm trying to write some Apps Script to pull only the email addresses which match from an array of companies into another sheet for processing. This should also remove the #company.com extension and leave me with just the username.
So on Sheet 1:
In Column E, we have the Company names under Header: "Company"
In Column D, we have the Email Addresses under Header: "Emails"
On Sheet 2:
In Column A, we need the Username result under Header: "Username"
Currently the below script which should have 2 results, comes back with:
this
Any help with this would be immensely appreciated as I'm losing my mind.
Thank you!
function pullUsernames() {
//Get Sheet1
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
//Set Values for Search
var valuesToWatch = ['Company1','Company2'];
var range = sheet.getRange(2,5,sheet.getLastRow()-1).getValues();
var emails = sheet.getRange(2,4,lr-1).getValues();
//For Loop to match values, etc.
for(var i=0; i < range.length; i++){
if(valuesToWatch.indexOf(range[i][0])){;
var targetSS = SpreadsheetApp.openById("1hpIIgkXMgrlOfYqfS4A3ro8BFQB02dAy5G40Y7vUI2c").getSheetByName("Sheet2");
var targetRange = targetSS.getRange(i+1,1,targetSS.getLastRow(),1);
var usernames = String(emails[i][0]).replace("#company.com", "")
targetRange.setValue(usernames[i][0]);
} //if
} //for
} //Function
There were a bunch of issues in your code and I decided to optimize them. Feel free to modify the code if needed.
Issues:
Both range and emails can be fetched together instead of separate
Brought targetSS outside the loop since it is only static based on your issue
I don't quite get your getRange, I assume you want to append the usernames on the last row? If so, then use appendRow instead.
Since I didn't use the array index now, I used includes instead to check if the data is in valuesToWatch.
Your email string manipulation is quite hard coded so I replaced it with a better solution, removing anything but the characters before #.
Code:
function pullUsernames() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
// update your targetSS, made it under same ss for easier testing
var targetSS = ss.getSheetByName("Sheet2");
// set values for search
var valuesToWatch = ['Company1', 'Company2'];
// get email and company columns in one go
var data = sheet.getRange(2, 4, sheet.getLastRow() - 1, 2).getValues();
// each row of data contains email and company formatted as [email, company].
data.forEach(function ([email, company]){
if(valuesToWatch.includes(company))
// remove anything from # onwards from email and append at last row
targetSS.appendRow([email.substring(0, email.lastIndexOf("#"))]);
});
}
Sample Data:
Sample Output:

Script to sent email from Google Sheet is sending multiple times

I used the tutorial here: https://developers.google.com/apps-script/articles/sending_emails
The problem I am having is that it sends the notifications many times (17, 25, 30 times.) I tried the "Improved" version as well, where it should only send an email if the column "Email_sent" isn't populated. The script populates the "email_sent" but that didn't prevent it from sending a bunch of times, even though with the "if" that shouldn't be possible.
I don't know what I could possibly be doing wrong that causes it to send so many times.
I had to modify the code slightly because when I use var row = data[i] and var emailAddress = row[0] it was not able to retrieve the email addresses.
If I take out the [i] and just use var row = data then it works. I don't know what difference that is causing or if it is related to the problem I am having.
I also changed numrow to sheet.getlastrow() instead of a static number because the number of rows in my data could change.
Here is my code, written as in the tutorial with the i
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var numRows = sheet.getLastRow()
var dataRange = sheet.getRange(3, 2, numRows);
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[0];
var message = 'You have unreleased time in LETS. Please review and release.';
var subject = 'Please review LETS time';
MailApp.sendEmail(emailAddress, subject, message);
}
}
This way fails to send, says it cannot find a recipient, and the debugger shows the emailAddress line returning blank. If I remove the [i] it runs, but every time I run it I get a ton of emails, and it should only send one per email address.
The syntax for getting ranges is getRange(row, column, numRows)
It expects the number of rows, rather than the last row as the third parameter.
Assuming that your last row is 6,
var dataRange = sheet.getRange(3, 2, numRows);
would mean "get 6 rows starting with number 3", or "get rows 3 to 8". But you won't have any data in row 7 and 8 - this throws you the error.
Just change your code to:
var startRow=3;
var dataRange = sheet.getRange(startRow, 2, numRows-startRow+1);

Sending an email with spreadsheet data

I'm currently trying to write an Apps Script function that sends an email when its Google Sheet is edited. My current problem is that the function only sends one column of data and I need it send both the date and amount of inventory. This is what I currently have, I'm thinking that maybe I need a nested loop in order for the function to print both columns. Any help would be great!
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(2, 1, 4, 2);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
//var data = dataRange.getSheetValues();
for (i in data) {
var row = data[i];
var message = row[1]; // Second column
var subject = "Inventory update";
MailApp.sendEmail("test#test.com", subject, message);
}
}
In the above code values of your cells from range "A2:B5" are stored in an array of array format in variable data i.e
var data = dataRange.getValues(); //This code results in the below
data = [["A2","B2"],
["A3","B3"],
["A4","B4"],
["A5","B5"]]
Where A2 corresponds to the value of cell A2, B2 to cell B2 and so on. To access the first row you would the following:
data[0] => ["A2","B2"]
Note: data[0] returns another array containing all the elements on row 1. Also, note the numbering starts from 0 not form 1
Now to access the first element of the first row, you would do the following:
data[0][0] => "A2"
So similarly in your above, code when you do this
var row = data[i]; where i = 0
row => ["A2","B2"]
Hence to get first column you would do
row[0] => "A2"
to get the second column you would do
row[1] => "B2"
Modify your message variable to look like this
message = message + row[0] +","+row[1]"\n"
Where in your appended the new row to the previous message with a comma delimiter and \n new line feed.
As of now, your mail app sends 1 email per each row. However, I don't believe that is the intended behavior. Below is your modified code
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(2, 1, 4, 2);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
//var data = dataRange.getSheetValues();
var message ="" //empty string
//Loop through each row and form CSV data
for (var i=0;i<data.length;i++) { //edited because:https://stackoverflow.com/questions/500504/why-is-using-for-in-with-array-iteration-a-bad-idea
var row = data[i];
message = message + row[0] +","+row[1]"\n"
}
// Send one email with all the rows
var subject = "Inventory update";
MailApp.sendEmail("test#test.com", subject, message);
}
The initial question did not insist on a coded solution.
Therefore, your exact usecase can be done without code, using this Gsheet addon:
https://reactor.isvery.ninja/
see the tutorial video in the bottom (send email from spreadsheet)

Insert Comment - GoogleSpreadsheets

I'm looking to insert comments onto a certain cell once a script has run.
The script I am using is to insert a calendar entry - however I only want it to do this once. To do this, I will get the script to check if a comment/note is entered onto the cell. In theory, this should be easy but I'm having trouble making it select the right cell... Can anyone help? My code is below.
I'm after the comment to go in the cell that corresponds with var = date.
If anyone can give me pointers, I'd really appreciate!
Cheers,
Pete
function CalendarInputIVNShortlist() {`
`var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 26); //What data will be used
var data = dataRange.getValues();
var cal = CalendarApp.getDefaultCalendar(); //Gets the correct calendar
for (i in data) {
var row = data[i];
var title = row[1]; // Column with Title
var desc = row[15]; // Column with Next Steps
var date = row[5]; //Column with Date
var invite = row[2] //Column with PDC Chairs & IVN Owner
var sent = row[12] //Check Sent
sheet.getRange(data[i], 5).setNote(Sent)
cal.createAllDayEvent(title, new Date(date), {description:desc,guests:invite});
var Comment = dataRange(date).setNote("Inputted")
There's a problem here:
sheet.getRange(data[i], 5)
The first parameter you've used, data[i], is an array (that you've already equated to row a few lines earlier). The getRange() method variance you are looking for expects two Numbers as parameters. If your intent was to add a note to column 5 of the row currently being references in your loop, then you want:
sheet.getRange(i+startRow, 5).setNote(sent);
Another issue with that particular line is with Sent; I assume you wanted to reference the variable you has set equal to row[12], just above, which had a small letter 's' in its name.
Next, there's something wrong here:
var Comment = dataRange(date).setNote("Inputted")
What is dataRange()? Unless it's another function in your script, that returns a Range object relevant to the contents of row[5], I would guess you intended this:
sheet.getRange(i+startRow, 5).setNote("Inputted");
sheet.getRange() needs 2 integers as parameters : the row number and the column number.
In your code you are trying to assign an array (data[i]) as row nuber...this cannot work.
Since it counts from startRow and since array are 0 indexed I would suggest you try like that :
sheet.getRange(startRow+i, 5).setNote(Sent)