I need to send an email from my sheets based on the first Column inputs (email ID's) and (which is dynamic row and gets updated based on the time). how can I return only A2:A length using the google script. Also, how can I do it in excel as well?
var formattedDate = Utilities.formatDate(new Date(), "GMT-6", "'Date: ' yyyy-MM-dd ' Time: ' HH:mm:ss ' CDT'");
var EMAIL_SENT = 'Email Success ! '+ "\n\n" + formattedDate;
/**
* Sends non-duplicate emails with data from the current spreadsheet.
*/function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Script (Beta)").activate();
var startRow = 2; // First row of data to process
var numRows = 120; // Number of rows to process
// Fetch the range of cells 'A' columns
var dataRange = sheet.getRange(startRow, 1, numRows, 3);
// 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[0]; // First column
var message = row[1]; // Second column
var emailSent = row[2]; // Third column
if (emailSent !== EMAIL_SENT) { // Prevents sending duplicates
var subject = '[Auto] The Process Has Not Yet Been Started';
if(emailSent =='')
break;
MailApp.sendEmail(emailAddress, subject, message, {htmlBody: message,
cc: 'abc#xyz.com',
bcc:'cde#xyz.com'});
sheet.getRange(startRow + i, 3).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
Logger.log(sendEmails2);
SpreadsheetApp.flush();
}}}
function A2A(col,sh,ss) {
var ss=ss || SpreadsheetApp.getActive();
var sh=sh || ss.getActiveSheet();
var col=col || 1;
return sh.getRange(2,col,sh.getLastRow()-1,1).getValues().filter(String).length;
}
To get the last row of the 'A' column you can get first all the values of the row:
var dataRange = sheet.getRange('A:A').getValues();
getValues() returns a two-dimensional array of values, indexed by row,
then by column
Since we have already set the column to be A we will need only one for to loop through the array:
var lastDataPosition = 0; // Create variable to set the last row of the column that has data
for (var i = 0; i < dataRange.length; ++i) {
if (dataRange[i] != '') { // Check if the array position has data
lastDataPosition = i + 1 // If the position has data in it -> assign that position to 'lastDataPosition' as the last one
}
}
*We add +1 to the array position since the first cell of the sheet is 1 and the first position of the array is 0
This is how you get the last row with data even if there are some blank cells in the middle.
For excel, I recommend you to create a new question with the proper tags.
Related
Given
Column G is having the expected return date(i.e. reminder date).
Column J is having email address stored
Column L is having return status
Need
Need to send the reminder email(email address Col J) on the reminder date(COl G) if the Column L (Return_Status) is blank.
I already have a code written, can't figure out the exact issue why it is not working.
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails() {
var today = new Date().toLocaleDateString(); // Today's date, without time
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 999; // Number of rows to process
// Fetch the range of cells A2:B999
//var dataRange = sheet.getRange(startRow, 1, numRows, 999)
//var dataRange= sheet.getRange("Form Responses 1!A1:L");
var dataRange= sheet.getRange(startRow,numRows)
// 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 = "dummy#gmail.com";
var subject = "RC Reminder # "+row[3];
var message = "Reminder for "+row[4]+" RC of vehicle"+row[3]+" handed over to "+row[5]+" against "+row[2]+" on "+row[0];
var emailSent = row[10];
var reminderDate = new Date(row[6]).toLocaleDateString();
if (reminderDate != today) // Skip this reminder if not for today
continue;
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
MailApp.sendEmail(emailAddress, subject, message,{name:'Sam'});
sheet.getRange(startRow + i, 11).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
In this line of code you're just getting the value of one cell
var dataRange= sheet.getRange(startRow,numRows)
getRange(row, column)
You should change it to:
var dataRange = sheet.getRange(startRow, 1, sheet.getLastRow()-1,sheet.getLastColumn())
getRange(row, column, numRows, numColumns)
This way you will only iterate through the values that are in your sheet and you will not work through empty data. If you have several sheets in your spreadsheet try consider to work with the one you have the data, accesing to the right one like this:
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('NAME OF YOUR SHEET');
getSheetByName(name)
How to auto send email based Column D "Today"
to Email on Column A with Subject of COlumn B and Body of Columnn C
I found a script quite similar to my condition, but it only send to a static email
Script Source
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Email"); // To only handle the trigger sheet
var startRow = 2; // 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];
if (row[2] === "Today") { // Trigger only if Column C is "Yes"
var emailAddress = row[0]; // First column
var message = row[1]; // Second column
var subject = "Bday ==" + row[2]; // Add "Yes" although by your trigger logic it will always say yes in the email
MailApp.sendEmail(emailAddress, subject, message);
}
}
}
And is it possile to make it compatible with my previous script
Link Source
this script about Dynamic Dependent Drop Down Lists
function onEdit(event)
{
var maxRows = false;
// Change Settings:
//--------------------------------------------------------------------------------------
var TargetSheet = 'Main'; // name of sheet with data validation
var LogSheet = 'Data1'; // name of sheet with data
var NumOfLevels = 4; // number of levels of data validation
var lcol = 2; // number of column where validation starts; A = 1, B = 2, etc.
var lrow = 2; // number of row where validation starts
var offsets = [1,1,1,2]; // offsets for levels
// ^ means offset column #4 on one position right.
// var maxRows = 500; // to set the last row of validation; delete this row if not needed
// =====================================================================================
SmartDataValidation(event, TargetSheet, LogSheet, NumOfLevels, lcol, lrow, offsets, maxRows);
// Change Settings:
//--------------------------------------------------------------------------------------
var TargetSheet = 'Main'; // name of sheet with data validation
var LogSheet = 'Data2'; // name of sheet with data
var NumOfLevels = 7; // number of levels of data validation
var lcol = 9; // number of column where validation starts; A = 1, B = 2, etc.
var lrow = 2; // number of row where validation starts
var offsets = [1,1,1,1,1,1,1]; // offsets for levels
// var maxRows = 500; // to set the last row of validation, delete this row if not needed
// =====================================================================================
SmartDataValidation(event, TargetSheet, LogSheet, NumOfLevels, lcol, lrow, offsets, maxRows);
}
function SmartDataValidation(event, TargetSheet, LogSheet, NumOfLevels, lcol, lrow, offsets, maxRows)
..... Etc etc
Sorry the script is so long, i got warning "your post mostly code"
i just post some of it here and you can check full script onLink Source
You can change the script as such to check the rows and send email based on value of column D:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Email"); // To only handle the trigger sheet
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow()-1; // Number of rows to process
// Fetch the range of cells A2:D
var dataRange = sheet.getRange(startRow, 1, numRows, 4)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
if (row[3] === "Today") { // Trigger only if Column D is "Today"
var emailAddress = row[0];
var subject = row[1];
var message = row[2];
MailApp.sendEmail(emailAddress, subject, message);
}
}
}
To use this in a trigger similar to your second script you need to create an Installable Trigger and specify the function name. For example, if you want to trigger the sending every 24 hours:
function createTimeDrivenTriggers() {
// Trigger every 24 hours.
ScriptApp.newTrigger('sendEmails')
.timeBased()
.everyHours(24)
.create();
}
I am having problems with a script that I wrote. It isn't throwing any errors however I am not receiving the emails. The goal of this script is to send an email if column G has value Y.
Column A = Organization Name
Column C= Days Aging
Column F= Email (where the email should be sent)
Column G= Status (where the Y will be)
function CheckPastDueAccounting() {
//Fetch Accounting Spreadsheet with past due accounts
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var lrow= ss.getLastRow();
for(var i=2;i<=lrow;i++);
var Status =ss.getRange(i,7);
var value = Status.getValue();
if (value == 'Y') {
var DaysAgingColumn = ss.getRange(i,3);
var DaysAging = DaysAgingColumn.getValue();
// Fetch Organization Name
var Organizations = ss.getRange(i,1);
var org = Organizations.getValue();
// Fetch the email address
var emailRange = ss.getRange(i,6);
var emailAddress = emailRange.getValue();
// Send Alert Email.
var message = 'Hi. Your account is past due ' + DaysAging + ' days.'; // Second column
var subject = 'Past Due Accounting Alert: ' + org;
GmailApp.sendEmail(emailAddress, subject, message);
}
}
Issue:
You should be enclosing the statements you want to run in loop between { }. Otherwise, the for loop is just incrementing the variable i and not running any of your desired code.
Moreover, after the for loop ends, the variable i is higher than the last row with content (lrow) which means that all calls to .getRange(i, columnIndex) refer to empty cells. Because of this, no email is sent, and no error is shown.
Solution:
function CheckPastDueAccounting() {
// Code before for loop starts
for(var i=2; i<=lrow; i++) {
// Code to run in loop (iterate through all rows with content)
}
// Code to run after for loop ends
}
Improving code:
Calling getRange(row, column) for individual cells, for each row in a for loop, is not the best way to iterate through rows with data.
It's much better to first (1) get all the values in the desired range, with getRange(row, column, numRows, numColumns) and getValues(), and then (2) iterate through the resulting 2D array, like this:
function CheckPastDueAccounting() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var lrow= ss.getLastRow();
var firstRow = 2;
var values = ss.getRange(firstRow, 1, lrow - firstRow + 1, 7).getValues();
for (var i = 0; i < values.length; i++) {
var row = values[i];
var value = row[6];
if (value == 'Y') {
var DaysAging = row[2];
var org = row[0]; // Fetch Organization Name
var emailAddress = row[5]; // Fetch the email address
var message = 'Hi. Your account is past due ' + DaysAging + ' days.';
var subject = 'Past Due Accounting Alert: ' + org;
GmailApp.sendEmail(emailAddress, subject, message); // Send Alert Email.
}
}
}
Reference:
for loop
getRange(row, column, numRows, numColumns)
Can anyone help me with sending an email via google scripts?
Here the challenge I am facing is that the range of the first column (email) may go up to 1000 lists of the email addresses. Although, now it's working fine (for now) how can I make it a dynamic range of list to be fed over my email lists to the script.
Code:
// This constant is written in column C for rows for which an email
// has been sent successfully.
var EMAIL_SENT = 'Email Success!';
/**
* Sends non-duplicate emails with data from the current spreadsheet.
*/
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Script (Beta)");
var startRow = 2; // First row of data to process
var numRows = 3; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 3);
// 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[0]; // First column
var message = row[1]; // Second column
var emailSent = row[2]; // Third column
if (emailSent !== EMAIL_SENT) { // Prevents sending duplicates
var subject = '[Auto] The Process Has Not Yet Been Started';
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 3).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
Doc Link
In order to make your range dynamic, you could use Sheet.getLastRow(), which returns the position of the last row with content.
Assuming that function sendEmails2 is the one your using for this, you would just have to modify the variable numRows. You would have to change this line:
var numRows = 3; // Number of rows to process
To this one:
var numRows = sheet.getLastRow() - startRow + 1;
Reference:
Sheet.getLastRow()
I hope this is of any help.
I've been using Google form to collect information to a workbook, then using that information to send customized emails back to the sender. I am a noob at coding, but I have managed to cobble together enough for this task. My problem is that, when it comes to a blank email cell it stops. I've tried to put in a loop to make it skip, with no success. Any help would be appreciated. This is the program I am using without a loop.
// This constant is written in column C for rows for which an email
// has been sent successfully.
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2000; // Number of rows to process
// Fetch the range of cells A2:B2001
var dataRange = sheet.getRange(startRow, 1, numRows, 2001)
// 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[0]; // First column
var message = row[1]; // Second column
var emailSent = row[2]; // Third column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = "Bounce Reply";
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 3).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
You can use string.match() function to determine if a cell is empty or not. Since you are looking for email address you might as well see if the cell has '#' sign. If not exclude the cell and continue on to the next cell like so:
if (emailAddress.match('#') === null){
continue; // skip this iteration of the loop and go to the next one
}
Your final code will look like:
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2000; // Number of rows to process
// Fetch the range of cells A2:B2001
var dataRange = sheet.getRange(startRow, 1, numRows, 2001)
// 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[0] // First column
if (emailAddress.match('#') === null){
continue; // skip this iteration of the loop and go to the next one
};
var message = row[1]; // Second column
var emailSent = row[2]; // Third column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = "Bounce Reply";
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 3).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
Edit
To check if something is empty or not you can try something like this.
if (message.match(/[a-zA-Z0-9_]/) === null) { //" /[a-zA-Z0-9_]/ " is regex to match any and every alphanumeric letter including underscore
continue; // skip this iteration of the loop and go to the next one
}
You can find more details on function match and regex here.
Hope that helps!