This program is supposed to iterate through a range of spreadsheet cells containing email addresses and then assign them to contact groups. It is very slow and keeps giving me a "transient error. Try again later". Many of the cells are empty and I figure that is the cause. Can you help me speed this up so I stop getting transient errors (after 20-30 cells). I tried to implement this if clause but It either creates an blank contact (wasting my quota) or throws a null error.
If clause to skip over empty cells:
if(cell != "" && cell != null){
My script:
function addContactstoGroup() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('NewEmails');
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var dataRange = sheet.getRange(2, 9, lastRow , lastColumn); //rows and columns start at 1, arrays start at 0.
var data = dataRange.getValues();
for (var i=1; i < lastRow; ++i){ //rows
var groupHeaderRange = sheet.getRange(i+1,9);
var groupHeader = groupHeaderRange.getValue();
for(var j=1; j < lastColumn; ++j){ //columns
var cell = data[i][j].getRange;
if(cell != "" && cell != null){
var groups = data[i][9];
var cell = sheet.getRange(i+2,j+9);
var contactGroup = data[i][0];
var emailAddress = data[i][j];
var contact = ContactsApp.createContact(null,null, emailAddress); // insert null http://stackoverflow.com/questions/20600852/how-to-add-a-contact-without-a-name-in-gas
var group = ContactsApp.getContactGroup(contactGroup);
group.addContact(contact);//or should this just be emailAddress
cell.clear();
};
groupHeaderRange.clear();
};
//}else{break;};
};
};
You would be my hero if you could help me fix:
1) Transient errors
2) If clause so it skips empty cells and does not run "ContactsApp.createContact"
var contact = ContactsApp.createContact(null,null, emailAddress); // insert null
Thank you!!! I've only been coding a few months and I don't understand why this keeps coming up.
Thanks!
Try changing var cell to var cell = data[i][j]; then your if statment should work.
Your transient error could be caused by an invalid email address. i.e. an email address that does not exist or some whitespace in an email address that you can't see.
You can find and remove whitespace by selecting the range containing the email addresses go to find replace. In the find field, put in 1 space and click replace all.
If you could provide a dummy spreadsheet with dummy email addresses it would be much easier to see if we could make your code more efficient.
Related
I have an emailer script that I would like to run for specified tabs and also make sure it skips any rows with blank values as it currently seems to break down as soon as it hits a blank row.
I have successfully built the script to work for one tab, but it seems to break down as soon as I try and get it to work for multiple tabs.
function reminders() {
var ss = SpreadsheetApp.openById("SHEET-ID");
var sheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName(("sheet_1","sheet_2","sheet_3")));
var editedCell = sheet.getActiveRange().getColumnIndex();
var dataRange = sheet.getDataRange();
var data = dataRange.getValues();
var text1 = 'Insert body of email here';
for (var i = 1; i < data.length; i++)
(function(val) {
var row = data[i];
var recipient = row[4];
var name = row[2];
var replyto = 'reply_to#email.com';
var body = 'Dear' + ' ' + name + ',' + '\n\n' + text1;
var subject = 'Hello World';
GmailApp.sendEmail(recipient, subject, body, {from:'reply_to#email.com', replyto:'reply_to#email.com'});
})(i);
}
This currently works for sheet_1 but does not work for sheet_2 or sheet_3.
Does anyone have any suggestions for how I can improve this script to send to multiple sheets and also skip blank rows?
You want to send emails using the values of column "C" and "E" from the Spreadsheet.
You want to run your script for the sheet names of "sheet_1", "sheet_2" and "sheet_3".
You want to skip the rows which have no values of the column "C" and/or "E".
If my understanding is correct, how about this modification?
Modification points:
It seems that when var sheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName(("sheet_1","sheet_2","sheet_3"))); is run, only "sheet_3" is retrieved.
In your case, I think that setActiveSheet() might not be required to be used.
Number of arguments of getSheetByName(("sheet_1","sheet_2","sheet_3")) is one.
When you want to use multiple sheets, please use each sheet name in the loop.
var editedCell = sheet.getActiveRange().getColumnIndex(); is not used in your script.
val of (function(val) { is not used in your script.
When you want to skip the empty rows, please put the if statement before GmailApp.sendEmail(). By this, the error is removed at GmailApp.sendEmail().
When above points are reflected to your script, it becomes as follows. Please think of this as just one of several answers.
Modified script:
Please copy and paste the following modified script to the script editor.
function reminders() {
var sheets = ["sheet_1","sheet_2","sheet_3"]; // Please set the sheet names here.
var ss = SpreadsheetApp.openById("SHEET-ID");
for (var s = 0; s < sheets.length; s++) {
var sheet = ss.getSheetByName(sheets[s]);
var dataRange = sheet.getDataRange();
var data = dataRange.getValues();
var text1 = 'Insert body of email here';
for (var i = 1; i < data.length; i++) {
var row = data[i];
var recipient = row[4];
var name = row[2];
if (!recipient || !name) continue; // Here, the empty rows are skipped.
var replyto = 'reply_to#email.com';
var body = 'Dear' + ' ' + name + ',' + '\n\n' + text1;
var subject = 'Hello World';
GmailApp.sendEmail(recipient, subject, body, {from:'reply_to#email.com', replyto:'reply_to#email.com'});
}
}
}
Note:
In this modified script, when "recipient" or "name" are not existing, the row is skipped.
When you send a lot of emails, please be careful the quotas of "Email read/write". You can see it at here.
References:
getSheetByName(name)
Quotas for Google Services
If I misunderstood your question and this was not the result you want, I apologize.
I'm trying to send a reminder for a weekly webinar with emails that live on a Google Sheet using Google's script editor/codelab. The link for the tutorial it's based off of is here: https://developers.google.com/apps-script/articles/sending_emails
In their second section of code they post, it is an improved version because after the email is sent it populates a column with "EMAIL_SENT" and should prevent a duplicate email being sent out because "EMAIL_SENT" occupies that space (as I understand it).
My problem is that after I run the script, I'm able to get the emails to send off (I used three email accounts and each one received it), but I also get an error that reads:
Failed to send email: no recipient (line 24, file "macros").
Macros is the name of the file. The other issue I'm having is that if I run the script again after EMAIL_SENT has populated, it still sends an additional email even though it's not supposed to.
I've tried making the object in the first portion of the code different numbers to try and capture the right data. After I got the right data in there I don't understand why the other portions won't work.
`// This constant is written in column C for rows for which an email
// has been sent successfully.
var EMAIL_SENT = 'EMAIL_SENT';
/**
* Sends non-duplicate emails with data from the current spreadsheet.
*/
function sendEmails_w_verification() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 116; // First row of data to process
var numColumns = 8;
var startColumn = 1;
// Fetch the range of cells as object
var dataRange = sheet.getRange(startRow, startColumn,
sheet.getLastRow(), numColumns);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[1]; // Second column
var message = "Thank you for registering for the webinar"; // Second
column
var emailSent = row[8]; // ninth column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = 'AFWERX Webinar Reminder';
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 9).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is
interrupted
SpreadsheetApp.flush();
}
}
}
Expected duplicates not to send and no error message of "Failed to send email: no recipient (line 24, file "macros")" when the email sent.
Your first no recipient error seems to be caused by how you're starting your for loop, if you switch it to i++ instead, the script runs fine. This is because by using ++i you're picking up an extra row which doesn't have any email address in it, causing it to throw the "no recipient" error you're getting.
The second issue with the script not being able to check against column 9 is because the range you defined is only 8 columns wide, not 9. I found this by using a simple Logger.log(emailSent) which came back as undefined, which is what you'd expect to see if the value isn't even being defined in the range at all.
// This constant is written in column C for rows for which an email
// has been sent successfully.
var EMAIL_SENT = 'EMAIL_SENT';
/**
* Sends non-duplicate emails with data from the current spreadsheet.
*/
function sendEmails_w_verification() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 1; // First row of data to process
var numColumns = 9;
var startColumn = 1;
// Fetch the range of cells as object
var dataRange = sheet.getRange(startRow, startColumn, sheet.getLastRow(), numColumns);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; i++) {
var row = data[i];
var emailAddress = row[1]; // Second column
var message = "Thank you for registering for the webinar"; // Second column
var emailSent = row[8]; // ninth column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = 'AFWERX Webinar Reminder';
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 9).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
I've changed the for statement to use i++ rather than ++i which fixes the "no recipient" error message.
for (var i = 0; i < data.length; i++) {
Then changed your var numColumns to 9 rather than 8 so that it can see the column you're trying to check with your if statement.
var numColumns = 9;
I have designed a google spreadsheet to help improve efficiency of material flow. I want to automatically sort the data by 2 different columns to prioritize critical parts that need to be received first once the entire row of data is entered. The problem I am having is that the data is sorting as soon as you enter one of the columns I am calling to sort but the columns I want to sort are not the last column of that row of data that needs to be entered. I am trying to use an if statement to not execute the sort until the last column has been entered else throw an error statement that says you must enter data in this column to proceed. Logically, the code makes sense to me but I have only an adequate understanding of computer language. I keep receiving an error in line 10 that the range is not found. I believe my error is the syntax in trying to call the last column. Any help would be greatly appreciated
**function autosort(){
// Variable Declaration
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var NewsheetName = SpreadsheetApp.getActiveSheet().getName();
var sheetName = sheet.getSheetByName(NewsheetName);
var lastCol = sheetName.getLastColumn();
var lastColBlank = SpreadsheetApp.getActiveSheet().getRange(lastCol).isBlank()
// Find range to sort
var range = sheetName.getRange("A2:G");
// Sorting algorithm
if (lastColBlank == false ){
range.sort([6,5]);
}
else {
throw ("error: If trailer # is unavailable, please enter N/A");
}
}**
Try this code:
function onEdit() {
var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var editedCell = sh.getActiveRange().getColumnIndex();
if(editedCell == 2) {
var range = sh.getRange("A2:B10");
var blank = range.isBlank()
var values = range.getValues();
Logger.log(values)
for (var i = 0; i<values.length; i++) {
//values.length returns 11 for eleven items
// values[10][0] would be the 11th row 1st column
Logger.log(values[i][1])
if (values[i][0] == "" || values[i][1] == "") {
//throw new Error("error: If trailer # is unavailable, please enter N/A");
var ui = SpreadsheetApp.getUi();
var response = ui.alert('If trailer # is unavailable, please enter N/A');
}else{
range.sort({column: 2});
}
}
}
}
If you'll look into the code, the sort depends on the second column to be edited. Then, will check the range if the is still a blanked cell.
Just apply your additional code to meet your goal and I think that will work.
Hope this helps.
I am trying to write a script in google sheets that will send one of two different emails based on the response to a multiple choice question. I can get my if/else statement to send either one or the other of the emails but it will not recognize the text of the multiple choice answer and send the correct email.
Here is the full script:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 1;
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 8)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var title = row[1]; // First column
var startDate = row[3]; // Second column
var endDate = row[4];
var description = row[2];
var location = row[6];
var eventImport = row[5];
var emailAddress = row[7];
var multchoice = row[8];
if (multchoice == "Part Time") {
var subject = "New Hire Part Time Email - " + startDate;
var emailBody = "Congradulations"
var htmlBody = "Congradulations! Part time person"
MailApp.sendEmail (emailAddress, subject, emailBody);
} else {
var subject = "New Hire Appointment - " + startDate;
var emailBody = "Congratulations! We are excited"
var htmlBody = "Congratulation! </i><br/> <br/> We are excited"
MailApp.sendEmail(emailAddress, subject, emailBody);
}
}
}
I believe the problem is here:
if (multchoice == "Part Time")
Any help is greatly appreciated! I am a novice
It looks like you are assigning your variables starting with '1' I stead of '0'. Start assigning them with 0 and counting up.
Without an example sheet to use, I won't be able to do a whole lot of debugging for you.
However, Apps Script comes with it's own debugger. Select the function you wish you debug and click the Little bug icon beside the play button.
Click on the sidebar where you want to set a breakpoint, where the code will stop executing.
Once it hits that breakpoint you can see all the variables currently within your scope. So the array, value, and i variables are visible to you.
Use this to your advantage and debug your code to find out where the issue is. Alternatively, you can use Logger.log() to log values at certain points within your code and then read back through the logs to try and determine where the problem lies.
The problem is not with your if/else statement. The problem is with how you are assigning your variables from your row[] array. While you use regular numbers in the getRange() function, the range that is returned is an array of those cells. Arrays always start with an index of [0]. Change var multchoice = row[8] to var multchoice = row[7] and your if/else statement will work (you'll want to change all of your other references, too).
If I copy/paste the information into both cells my script runs correctly and matches the strings in the cells to the correct row for the user so I can lookup their email. If I let my google form fill the first cell however the data in the two cells no longer matches. I'm probably overlooking something obvious about comparing the strings but hopefully someone can point me in the right direction. Here is the code I have so far.
var rows = SpreadsheetApp.getActiveSheet().getLastRow();
var cell = SpreadsheetApp.getActiveSheet().getRange(rows, 2);
var value = cell.getValue().toString();
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.setActiveSheet(ss.getSheets()[1]);
var sheet;
var teacher;
var cc = "no match";
for(var h=1; h <= ss.getLastRow(); h++)
{
sheet = ss.getActiveSheet().getRange(h, 2);
teacher = sheet.getValue().toString();
if (value == teacher)
cc = ss.getActiveSheet().getRange(h, 1).getValue().toString();
}
Try to use watchdog (clicking on line number) or some message box to see what happens
i.e. Browser.msgBox(teacher); bebore testing the value of value ^^
and may be don t use the "value" as a variable name, it could generate problem to execute the script.