Issue with onEdit after sending email in google sheets - function

here is my code in google script:
function Send(){
Browser.msgBox("Send");
}
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var lr = sheet.getLastRow();
var dataRange = sheet.getRange(startRow, 1, lr-1, 6);
var data = dataRange.getValues();
for (var i = 0; i < data.length; i++) {
var row = data[i];
var name = row[0];
var emailAddress = row[1];
var date = row[2];
var city = row[3];
var status = row[6];
if (emailAddress.match('#') === null){
continue;
};
var subject = row[4];
var message = "Hey " + name + ", welcome in the team " + row[5];
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(i+2,7).setValue("Sent");
}
}
Until here everything works fine. I would like then that when "Sent" appears in the 7th column, that the whole row where "Sent" is in, is moved to another tab.
function onEdit(e) {
var ss = e.source;
var s = ss.getActiveSheet();
var r = e.range;
var actionCol = 7;
var nameCol = 7;
var rowIndex = r.getRowIndex();
var colIndex = r.getColumnIndex();
var colNumber = s.getLastColumn()-1;
if (e.value == "Sent" && colIndex == actionCol) {
var targetSheet = s.getRange(rowIndex, nameCol).getValue();
if (ss.getSheetByName("Welcome")) {
var targetSheet = ss.getSheetByName("Done");
var targetRange = targetSheet.getRange(targetSheet.getLastRow()+1, 1, 1, colNumber);
var sourceRange = s.getRange(rowIndex, 1, 1, colNumber);
sourceRange.copyTo(targetRange);
s.deleteRow(rowIndex);
}
}
}
**If I manually write "Sent" in the 7th column, the row is moved to the other sheet. But when I run the first function and that "Sent" appears in that column, the onEdit function doesn't work.
So basically both functions work but not together at the same time.
Does someone know a fix for this?**

Issues:
You are trying to trigger an onEdit function via a script but that's not how triggers work. The official documentation states the following:
The onEdit(e) trigger runs automatically when a user changes the value
of any cell in a spreadsheet.
Namely, onEdit triggers are activated only by user actions, not by scripts nor formulas.
You don't need a separate function to check if the value is Sent and then delete the row with another function. After the email is sent you can move the data and delete the row, all within the same function.
Last but not least, when deleting rows iteratively we change the structure of the sheet and therefore the data input does not match the updated structure. To alleviate this issue, we can store the indexes of the rows we want to delete in an array, and then using that array delete the rows backwards.
Solution:
Assuming your codes work separately, this should also work:
function myFunction() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("Welcome");
var targetSheet = ss.getSheetByName("Done");
var startRow = 2;
var lr = sheet.getLastRow();
var dataRange = sheet.getRange(startRow, 1, lr-1, 6);
var data = dataRange.getValues();
var colNumber = sheet.getLastColumn()-1;
var delRows = [];
for (var i = 0; i < data.length; i++) {
var row = data[i];
var name = row[0];
var emailAddress = row[1];
var date = row[2];
var city = row[3];
var status = row[6];
if (emailAddress.match('#') === null){
continue;
};
var subject = row[4];
var message = "Hey " + name + ", welcome in the team " + row[5];
MailApp.sendEmail(emailAddress, subject, message);
var targetRange = targetSheet.getRange(targetSheet.getLastRow()+1, 1, 1, colNumber);
var sourceRange = sheet.getRange(i+startRow, 1, 1, colNumber);
sourceRange.copyTo(targetRange);
delRows.push(i+startRow);
}
// delete rows in reverse order
delRows.reverse().forEach(ri=>{sheet.deleteRow(ri)});
}
you don't need the onEdit function anymore so you can delete it.

Related

Not able to copy sheet1 data to sheet2 in specific format

https://docs.google.com/spreadsheets/d/18odtLaamxJISS7Gq-N-xPxVu1Fk55AYQoFojkmIgxbM/edit#gid=0
function myFunction() {
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Messages from BOs");
var startRow = 4; // First row of data to process
var numRows = 1; // Number of rows to process
// Fetch the range of cells A4:C3
var dataRange = sheet.getRange(startRow, 1, numRows, 3);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i in data) {
var row = data[i];
var emailAddress = row[0]; // First column
var subject = row[1];
var message = row[2]; // Second column
MailApp.sendEmail(emailAddress, subject, message);
}
for (var i in data, i++) {
var row1 = data[i];
Browser.msgBox(data[i+1])
/**
var emailAddress1 = row[0]; // First column
var subject2 = row[1];
var message3 = row[2]; // Second column
*/
var ad = row1;
var ts = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Test');
ts.getRange(startRow, i+1 ).setValue(row1);
//i = i + 1;
}
}
}
Here i wanted to update sheet2 every time when email send to "Recipient EMAL ID" to the new row of sheet2.
Please see my google sheet. I tried below code but it does not work well. If any who can help me in solve this problem.
Try to change:
ts.getRange(startRow, i+1 ).setValue(row1);
with:
ts.appenRow(row1);
https://developers.google.com/apps-script/reference/spreadsheet/sheet#appendRow(Object)
This is a lot simpler:
function sendEmails() {
const ss = SpreadsheetApp.getActive()
var sh = ss.getSheetByName("Messages from BOs");
var ts = ss.getSheetByName('Test');
var sr = 4; // First row of data to process
var rg = sh.getRange(sr, 1, 1, 3);
var vs = rg.getValues();
vs.forEach(row => {
MailApp.sendEmail(row[0], row[1], row[2]);
ts.appendRow(row);
});
}

how can you use a gmail script to attach more than one image at a time. below is an example of a working script to attach one image

I'm trying to set up a Google Sheet with some data to email images. I have the code working below to send a single image attachment but I would like to send more than one image at a time if it is possible. How could I change the code below to work with multiple images?
function emailImage(){
var EMAIL_SENT = "EMAIL_SENT";
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = sheet.getLastRow();
// Fetch the range of cells
var dataRange = sheet.getRange(startRow, 1, numRows, 5)
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[0]; // First column
var subject = row[1]; // Second column
var message = row[2]; // Third column
var image = UrlFetchApp.fetch(row[3]).getBlob(); // Fourth column
var emailSent = row[4]; // Fifth column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
MailApp.sendEmail(emailAddress, subject, message, {attachments: [image]});
sheet.getRange(startRow + i, 5).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
This is just a snippet to help you along:
var image1 = UrlFetchApp.fetch(row[3]).getBlob();
var image2 = 'However you wish to get it';
var options = { attachments: [] };
option.attachments.push(image1);
option.attachments.push(image2);
MailApp.sendEmail(emailAddress, subject, message, options);
With the help of #MetaMan I was finally able to get this working....
function emailImage(){
var EMAIL_SENT = "EMAIL_SENT";
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = sheet.getLastRow();
// Fetch the range of cells
var dataRange = sheet.getRange(startRow, 1, numRows, 6)
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[0]; // First column
var subject = row[1]; // Second column
var message = row[2]; // Third column
var image1 = UrlFetchApp.fetch(row[3]).getBlob();
var image2 = UrlFetchApp.fetch(row[4]).getBlob();
var emailSent = row[5]; // Fifth column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
MailApp.sendEmail(emailAddress, subject, message, {attachments: [image1, image2]});
sheet.getRange(startRow + i, 6).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}

How to pick the value numbers from another sheet using google app script?

I have 2 google sheet tabs, first sheet1 have col A - Email address, Col B - message, Col C - status.
and second sheet2 have only one column Col A - voucher code, I have insert all my necessary numbers in sheet2 Col A. So each time I run my script will send email out and automatically pick the numbers from sheet2 base on the last row of sheet1 data. Email sent without issue, but I fail to get voucher code data from sheet2 Col A in my email.
var EMAIL_SENT = 'EMAIL_SENT';
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
var sheet2 = SpreadsheetApp.getActive().getSheetByName("Sheet2");
var strRow2 = 2;
var numRows2 = 2;
var dataRange2 = sheet2.getRange(strRow2, 1, numRows2, 1)
var data2 = dataRange2.getValue();
for (var j = 0; j < data2.length; ++j) {
var row2 = data2[j];
var code = row2[0];
}
var startRow = 2;
var numRows = 2;
var dataRange = sheet.getRange(startRow, 1, numRows, 3);
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[0];
var message = row[1] + "\n" + code // this code no working
var emailSent = row[2];
if (emailSent !== EMAIL_SENT)
var subject = 'Sending emails from a Spreadsheet';
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 3).setValue(EMAIL_SENT);
SpreadsheetApp.flush();
}
}
}
In order to find the last row that has content you should use: getLastRow().
Here is the solution:
function sendEmail() {
var ss = SpreadsheetApp.getActive();
var sh1 = ss.getSheetByName("Sheet1")
var sh2 = ss.getSheetByName("Sheet2")
var EMAIL_SENT = 'EMAIL_SENT';
var sh1_LR = sh1.getLastRow();
var sh1_EA = sh1.getRange(sh1_LR,1).getValue();
var sh1_M = sh1.getRange(sh1_LR,2).getValue();
var sh2_V = sh2.getRange(sh1_LR,1).getValue();
try{
MailApp.sendEmail(sh1_EA, sh1_M, sh2_V);
sh1.getRange(sh1_LR,3).setValue(EMAIL_SENT);
}
catch(e)
{Logger.log("sendEmail failed")}
}

send mail with attachment in each row on google app script

I use attachment in each cell to send mail auto.
Note:
column 0: Firstname Column 4: Email Address Colum 5: Year Column 6: File Attachment.
var EMAIL_SENT = 'EMAIL_SENT';
//Sends non-duplicate emails with data from the current spreadsheet.
function autosendEmails() {
var ws = SpreadsheetApp.openById('Your Sheet Id');
var sheet= ws.getSheetByName('Mail Merge');
var startRow = 2; // First row of data to process
var numRows = ws.getLastRow(); // Number of rows to process // Fetch the range of cells E2:H3
var dataRange = sheet.getRange(startRow, 1, numRows, 7);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
// var FileID = DriveApp.getFileById('Your File Id')
for (var i = 0; i < data.length; i++) {
var row = data[i]; var emailAddress = row[4]; // First column
var Subjectmail ="Test mail"
var bodyemail = "Dear"
var pdfname = row[6];
var emailSent = row[7]; // Four column
if (emailSent !== EMAIL_SENT) {
// Prevents sending duplicates
var subject = 'Test mail';
MailApp.sendEmail(emailAddress, Subjectmail, bodyemail, {attachments: pdfname});
sheet.getRange(startRow + i, 8).setValue(EMAIL_SENT); // Make sure the cell is updated right away in case the script is interrupted SpreadsheetApp.flush();
}
}
}
Taking into consideration you're retrieving the file name from var pdfname = row[6]; , then what you must do to attach the file to your mail and send it, it's to retrieve the actual file from your drive and putting it into an array as I did in this example:
// Inside your function, just change this line
function autosendEmails() {
...
MailApp.sendEmail(emailAddress, Subjectmail, bodyemail, {
attachments: buildAttachment(pdfname) // Call this function to be able to send an attachment file
});
...
}
// Add this function to your code
function buildAttachment(pdfname){
// Initialize the array
var fileArr = [];
// Get the file form your drive
var getMyFile = DriveApp.getFilesByName(pdfname).next();
// build an array
fileArr.push(getMyFile);
// return the file within an array
return fileArr;
}
Reference
This post could help you, too.
Docs
Class MailApp
Class DriveApp
This might work better for you:
Read the comments for explanation.
function autosendEmails() {
var ws = SpreadsheetApp.openById('Your Sheet Id');
var sheet= ws.getSheetByName('Mail Merge');
var startRow = 2; // First row of data to process
var dataRange = sheet.getRange(startRow, 1, sheet.getLastRow()-1,sheet.getLastColumn());//you were missing your last column and you were grabbing an empty row and the end of your list because the third parameter is the number of rows in the data not the number of rows in the sheet.
var data=dataRange.getValues();
for (var i=0;i<data.length;i++) {
var row=data[i];
var emailAddress = row[4]; // First column
var Subjectmail ="Test mail"
var bodyemail = "Dear"
var pdfname = row[6];
var emailSent = row[7]; // Four column
if (emailSent !== "EMAIL_SENT") {
MailApp.sendEmail(emailAddress, Subjectmail, bodyemail, {attachments: ["an array of files"]});//attachments should be an array of files not an array of filenames
sheet.getRange(startRow + i, 8).setValue(EMAIL_SENT);
}
}
}
This is an example I normally use
function SendMailFC() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var message ="HELLO"
for (var i = 2; i <= 3; i++) {
var row = values[i];
var mail = row[7];
var name = row[4].substring(0,row[4].indexOf(" ",row[4].indexOf(" ")+1));
var company = row[1].substring(0,row[1].indexOf(","));
var Greeting = 'Hello ' + name+',<br><br>';
var stat = row[10];
var subject = "SUBJECT";
if(stat){
GmailApp.sendEmail(FROM, subject, "", {htmlBody: '<html>'+greeting+message+'</html>'} );
}
}

Google Apps Script: sendEmail from sheet using cc and/or bcc, and avoid return of EMAIL_SENT to sheet

I have a script that sends an email out to addresses on a sheet and then returns an entry in a column in the sheet that reads EMAIL_SENT.
function sendEmail()
{
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = sheet.getLastRow();
var EMAIL_SENT = "EMAIL_SENT";
var dataRange = sheet.getRange(startRow, 1, numRows, 2000)
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i)
{
var row = data[i];
var name = row [0].split(",")[1];
var emailAddress = row [2];
var Setting = Utilities.formatDate(new Date(row [2]), "CST", "MM-dd-YYYY");
var Place = row [4];
var emailSent = row[5];
if (emailSent != "EMAIL_SENT")
{
var message = "message body";
var subject = "Email to Client";
MailApp.sendEmail
(emailAddress, subject, message,
{htmlBody:message,
cc:'internalemail#internalemail.com'});
sheet.getRange(startRow + i, 6).setValue(EMAIL_SENT);
SpreadsheetApp.flush();
}}}
As you can see from the script, I am also wanting to cc a copy of the email to an internal email address, but avoid the return of the EMAIL_SENT to the sheet for this internal email.
The script as written above sends two emails, but it does not seem to send the cc'd email to the internal email address, and it returns an instance of 'EMAIL_SENT' to the column in the source sheet.
I commented out some of your code and made some notes. Without seeing the sheet you were working from, it's a bit challenging to figure out where the error was, but this should work.
function sendEmail() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = sheet.getLastRow();
var EMAIL_SENT = "EMAIL_SENT";
var dataRange = sheet.getRange(startRow, 1, numRows, 5/*2000*/); //Confused why you were selecting 2000 columns.
var data = dataRange.getValues();
for (var i = 0; i < data.length; i++) { //switched to i++ instead of ++i
//var row = data[i]; This isn't needed
var name = data[i][0]; //row [0].split(",")[1];
var emailAddress = data[i][1]; //row [2];
var Setting = Utilities.formatDate(new Date(/*row [2]*/), "CST", "MM-dd-YYYY"); //Looks like you were creating a Date from the email address (row[2])...?
var Place = data[i][3];
var emailSent = data[i][4];
if (emailSent != "EMAIL_SENT" && emailAddress != "") {
var message = "message body";
var subject = "Email to Client";
MailApp.sendEmail(emailAddress, subject, message,{htmlBody:message, cc:'internalemail#internalemail.com'});
sheet.getRange(startRow + i, 5).setValue(EMAIL_SENT);
SpreadsheetApp.flush();
}
}
}
Here is how I would organize the data, but you can obviously adapt to your needs. When setting dataRange, I grabbed 5 columns as the data only extends to column E.