I'm trying to get emails from my Google contacts list using a range of cell values.
I've managed to do this with one value but not with a range/list of values.
In my example the cell G2 contains the name John Doe, I have managed to get the value from G2, search my contacts and return the corresponding email. The next step is to then use that return value and write it to another cell in the same sheet, I have also achieved this (writes the email address to N2).
I can't figure out how to do this for a range of of cells, I've tried numerous different approaches but keep getting errors.
The below code works perfectly only for the first cell value, I've tried changing the range to (2, 7, 10, 1) to get the first 10 cell values, and its seems that part works fine, but I'm not sure what the correct method is to then go through this array and get the email addresses, and lastly running a loop to write the addresses to a range of cells.
To sum up I'm trying to get a range of names from G2:G12, convert these names to email addresses, and write the results to N2:N12.
My example below can be reproduced by copying the code into a new sheets doc, nameing the sheet "Main", adding a name to the G2 cell and running the code.
function getEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getSheetByName('Main');
var EmailRange = sheet.getRange(2, 7, 1, 1)
var EmailAddress = EmailRange.getValues()
var contacts = ContactsApp.getContactsByName(EmailAddress);
var email = contacts[0].getEmails()[0].getAddress();
Logger.log(email);
return email
}
function writeEmailsToSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getSheetByName('Main');
var results = getEmail();
var range = sheet.getRange(2, 14, 1, 1);
range.setValue(results);
}
To give you an idea, you can try the following script:
UPDATE
Here is the updated script, you can use the continue statement. This will break the iteration in the loop if the condition occurs and will continue with the next one.
function getEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getSheetByName('Main');
var emailRange = sheet.getRange("G2:G12")
var emailAddress = emailRange.getValues();
for (var i=0; i<emailAddress.length; i++){
var contacts = ContactsApp.getContactsByName(emailAddress[i]);
if (contacts != ""){
var email = contacts[0].getEmails()[0].getAddress();
sheet.getRange(i+2,14).setValue(email)
}
else{
sheet.getRange(i+2,14).setValue("Not found")
continue
}
}
}
Related
I'm trying to write a script that will allow me to email a list of 150 employees with their individual sales data for the week.
At the moment I have a main front sheet with a Column for Email, Subject, and Store number. Each store number correlates to a Sheet (tab) with the same name, for example joe#gmail.com at store number 5070 has a tab named '5070' with changing data.
The problem I'm having is referencing the changing variable sheet name.
function sendEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet1=ss.getSheetByName('Sheet1');
var n=sheet1.getLastRow();
for (var i = 2; i < n+1 ; i++ ) {
var emailAddress = sheet1.getRange(i,1).getValue();
var subject = sheet1.getRange(i,2).getValue();
var message = sheet1.getRange(i,3).getValue();
MailApp.sendEmail(emailAddress, subject, message);
}
}
I am very new to the whole thing and have been searching around but have not had much luck. Thank you in advance!
You can't send a sheet. You can send only a link to the sheet.
If you replace this:
var message = sheet1.getRange(i,3).getValue();
with this:
var sheet_name = sheet1.getRange(i,3).getValue();
var sheet = ss.getSheetByName(sheet_name);
var message = sheet.getUrl();
Your recipients will get the link to the spreadsheet (a whole sheet, not even to the particular sheet).
To send a link to a particular sheet of the spreadsheet you need a bit more complicated solution:
var sheet_name = sheet1.getRange(i,3).getValue();
var sheet = ss.getSheetByName(sheet_name);
var message = getSheetUrl(sheet);
function getSheetUrl(sht) {
// credits: https://webapps.stackexchange.com/questions/93305/
var ss = SpreadsheetApp.getActive();
var url = '';
sht = sht ? sht : ss.getActiveSheet();
url = (ss.getUrl() + '#gid=' + ss.getSheetId());
return url;
}
But all your recipients will see all the spreadsheet anyway with all its sheets. In case this is not the thing you want you have three options:
Option 1 -- Make a new spreadsheet, copy the data into it and send the link to this new spreadsheet.
Option 2 -- Make PDF from the sheet and send it. Actually you will need to perform Option 1 first, convert the new spreadsheet to PDF, and delete the new spreadsheet after you send it (as PDF).
Option 3 -- make a HTML table (or text table, why not?) from the data of the sheet and send the table.
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:
I'm collecting data from a Google Form that will be used in formulas that calculate costs and mileage. I've used =QUERY to bring the responses to another sheet 'Event Calculator'. When I run the forEach loop to get the data, it picks up cells with a formula.
I would like my code to find the last row with data and pull some numbers from cells to use in an email that will be sent right after they submit the form (on a trigger).
Is there a way to find the last row and then run the forEach loop? or am I going about this all wrong?
I've tried using if statements and forEach, but don't seem to have the correct order and am unable to just find the last row with data in it, not a formula.
The expected results are a single line of data that can be placed in an email function to send the results of the formulas to the respondent.
I've tried using the forEach loop, but it returns rows that contain formulas. I have tried if statements but cannot seem to get it to work with the forEach loop to get the data.
function travelReport() {
// get data from the Sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Event Calculator');
var allRange = sheet.getDataRange();
var allData = allRange.getValues();
// remove the header row
allData.shift();
// loop over rows of data
allData.forEach(function(row) {
// get data
var email = row[0];
var eventName = row[1];
var coordName = row[2];
var startName = row[3];
var destinationName = row[4];
function travelReport() {
// get data from the Sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Event Calculator');
var allRange = sheet.getDataRange();
var allData = allRange.getValues();
// remove the header row
allData.shift();
// loop over rows of data
allData.forEach(function(row) {
The results so far is that the forEach loop picks up all the rows I have a formula in. Several errors occur when I try to add code to find the last row with data.
Try this approach:
function travelReport(e) {
var ss=SpreadsheetApp.getActive();
Logger.log(e);
//I assume timestamp is actually e.values[0]. But you can just look at Logger.log to figure it out.
var email=e.values[1];
var eventName=e.values[2];
var coordName=e.values[3];
var startName=e.values[4]
var destinationName=e.values[5];
GmailApp.sendEmail(email, subject, body, options);//Presumably you know how to configure all of this
}
function createTrigger(name) {
var ss=SpreadsheetApp.getActive();
if(!isTrigger(name)) {
ScriptApp.newTrigger(name).forSpreadsheet(ss.getId()).onFormSubmit().create();
}
}
function isTrigger(funcName){
var r=false;
if(funcName){
var allTriggers=ScriptApp.getProjectTriggers();
for(var i=0;i<allTriggers.length;i++){
if(funcName==allTriggers[i].getHandlerFunction()){
r=true;
break;
}
}
}
return r;
}
Want a more precise answer...Give me more details.
I'm writing a script to loop through each sheet in one spreadsheet and copy data from specific cells into a corresponding sheet on another spreadsheet. I am getting an error on line 18 of the below code, however, stating that it can't call the getLastRow method of null. I used a couple of Logger.log lines to check my variables and see that targetSheet is coming back as null. Any advice on what I've got wrong?
//Export each sheet's daily data to another sheet *Test Version*
function exportReports() {
var sourceSS = SpreadsheetApp.getActiveSpreadsheet();
//Open Back Production Record *Test Version*
var targetSS = SpreadsheetApp.openById("1ZJKZi-UXvqyGXW9V7KVx8whxulZmx0HXt7rmgIJpUY4");
var allSourceSheets = sourceSS.getSheets();
//For-Loop to loop through hourly production sheets, running the move data for-loop on each
for(var s in allSourceSheets){
var loopSheet = allSourceSheets[s];
var loopSheetName = loopSheet.getSheetName();
var targetSheet = targetSS.getSheetByName(loopSheetName);
Logger.log(s);
Logger.log(loopSheet);
Logger.log(targetSheet);
Logger.log(loopSheetName);
var targetRow = targetSheet.getLastRow()+1;
var currentDate = Utilities.formatDate(new Date(), "GMT-5", "MM/dd/yy");
targetSheet.getRange(targetRow, 1).setValue(currentDate);
//For-Loop to move data from source to target
for(var i=6;i<=10;i++){
var sourceRange = sourceSheet.getRange(i, 2);
var targetRange = targetSheet.getRange(targetRow, i-4);
var holder = sourceRange.getValue();
targetRange.setValue(holder);
}
}
}
Per the documentation on getSheetByName, if the target sheet name does not exist, then you get null as a return value.
getSheetByName(name)
Returns a sheet with the given name.
If multiple sheets have the same name, the leftmost one is returned. Returns null if there is no sheet with the given name.
So, the desired sheet with name specified by loopSheetName does not exist in the target workbook. Perhaps someone has created a new sheet, or renamed an existing sheet in the source workbook.
You haven't asked about it, but you can improve the performance of your copy code as well, by reading the inputs as a multi-row range array, creating a row array to hold the results, and writing that once:
var sourceData = sourceSheet.getRange(6, 2, 5, 1).getValues(); // (6,2) through (10, 2)
var output = [];
// Transpose row array to column array (could use other functions, but this is easier to understand)
for(var i = 0; i < sourceData.length; ++i) { output.push(sourceData[i][0]); }
targetSheet.getRange(targetRow, 2, 1, output.length).setValues([output]); // i0 = 6 -> 6 - 4 = 2
I am stuck at a point in some code and need some expert help. I want to reference column "E" on the sheet "Form Responses", which will return a name of a person. The same name can be found in column "A" of sheet "Email". In column "B" of sheet "Email" will be the email address that I want to send data to. I am stuck at how to produce this email address. Here is what I have so far...
function emailData(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var responses = ss.getSheetByName("Form Responses");
var lastRow = responses.getLastRow();
var values = responses.getRange("A"+(lastRow)+":AK"+(lastRow)).getValues();// get the range and values in one step
var headers = responses.getRange("A1:AK1").getValues();// do the same for headers
var recipient = responses.getRange("E"+(lastRow)).getValues();
var emailSheet = ss.getSheetByName("Email");
var names = emailSheet.getRange("A2:A20").getValues();
var emails = emailSheet.getRange("B2:B20").getValues();
var subject = "Capacity Campaign Form";
var message = composeMessage(headers,values);// call the function with 2 arrays as arguments
Logger.log(message);// check the result and then send the email with message as text body
MailApp.sendEmail(recipient,subject,message);
}
function composeMessage(headers,values){
var message = 'Here is the data from the form submission:'
for(var c=0;c<values[0].length;++c){
message+='\n'+headers[0][c]+' : '+values[0][c]
}
return message;
}
I must give props to #Serge for helping me with the array. Alas, any help that you could provide would be awesome!
You've got the names and email addresses you need to search, in two 2-dimensional arrays. Each of those arrays is an array of rows. A simple search would be this:
var email = ''; // If we don't find a match, we'll fail the send
for (var row=0; row < names.length; row++) {
if (names[row][0] == recipient) {
email = emails[row][0];
break; // end the search, we're done
}
}
...
MailApp.sendEmail(email,subject,message);
There are more elegant ways to do this, I'm sure, but this should work for you.