Google Script E-mail confirmation - google-apps-script

My goal is to have a form that fills out a spreadsheet. Part of the form will have an e-mail address and another with is task complete. I want it to be if I switch the spreadsheet from no to yes under task complete to e-mail the user with a confirmation saying so. I don't know if it is possible but any help would be appreciated.
Edit :
This code is what I have down now to do the task. I like the way it is setup up but there are 2 major issues that I want to try and solve. First being when the script runs lets say I skip over a row the script will fail and not keep trying more entries down the rows. Second issue is I am not sure how to control who is sending the script e-mail past where it asks you to okay and run the script the first time.
// This constant is written in column O for rows for which an email
// has been sent successfully.
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 1000; // Number of rows to process
// Fetch the range of cells M2:N1000
var dataRange = sheet.getRange(startRow, 1, numRows, 1000)
// 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[12]; // First column
var message = row[13]; // Second column
var emailSent = row[14]; // Third column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = "Help Desk Completion Response";
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 15).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}

The e-mail will always be sent as the user that runs the script. You can have the script run as the result of an installable trigger which you can set on any Google account with access to the script and the script will then send the e-mail as that Google account. For example, have the script run once a day using a time-based trigger and check the values for EMAIL_SENT and TASK_COMPLETE, if the task is complete but the e-mail is not sent, then have the script send an e-mail. This should also solve the empty row problem because when TASK_COMPLETE is empty rather than "Yes" it will not try to send an e-mail.
If you want to make the script send an e-mail immediately you will need an edit-based trigger. In this case you may not even need to load the entire spreadsheet but a simple e.range.offset() may suffice.
Something like:
//This constant is written in column O for rows for which an email
//has been sent successfully.
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var columnNumber = e.range.getColumn(); //check if the changed value is TASK_COMPLETE
if(columnNumber = 5 && e.value = "Yes") {
var row = e.range.offset(0, -5, 1, sheet.getLastColumn()).getValues();
var emailAddress = row[12]; // First column
var message = row[13]; // Second column
var emailSent = row[14]; // Third column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = "Help Desk Completion Response";
MailApp.sendEmail(emailAddress, subject, message);
e.range.offset(0,9).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
Of course the exact offsets depend on where exactly in your spreadsheet things are located.

Related

Send emails to a specific email address only when row is not empty

I have a code that sends out emails to a specific email address (in this case lets say its myemailaddress#gmail.com) based on the values in my Google Sheet tab named 'Send Emails [Team A]'. It runs when I click on the menu item 'To Team A'. The code is sending out emails fine, however it also runs on rows that are blank, thus sending out blank emails to myemailaddress#gmail.com. The sheet will be updated from time to time which is why I did not limit the range until a specific row. Is there a way to make the code run only on rows that are not blank?
Here's the code that I'm using:
function onOpen() {
const ui = SpreadsheetApp.getUi();
ui.createMenu("Send Emails")
.addItem("To Team A", "toTeamA")
.addToUi();
// This constant is written in column C for rows for which an email
// has been sent successfully.
var EMAIL_SENT = "Email Sent";
function toTeamA() {
var sheet = SpreadsheetApp.getActive().getSheetByName("Send Emails [Team A]");
var startRow = 2; // First row of data to process would be '2' because the first row is header
var numRows = 1000; // Number of rows to process
var dataRange = sheet.getRange('A2:D') // Gets the data range
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = "myemailaddress#gmail.com";
var subject = row [1]; // Second column
var message = row [0]; // First column
var emailSent = row [2]; // Third column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 3).setValue(EMAIL_SENT);
// Makes sure cell is updated right away with "Email Sent" in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
Any help is much appreciated!
Sure, assuming your rows are empty, e.g. rows 1-100 contain content, whereas 101 onwards it is empty. You can find the last row with data using sheet.getLastRow(), see docs.
So instead of doing sheet.getRange("A2:D") you can do sheet.getRange("A2:D"+sheet.getLastRow()) which should fix the problem.

I'm trying to use paypal IPN with Google Sheets and Gmail to set up an automated email response when a buyer purchases a digital download but too hard

I've been successful getting the paypal ipn data to my google sheets using a variation of a script i found online.
function doPost(e) {
var rowData = [];
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet()
rowData.push(new Date(e.parameter.payment_date));
rowData.push(e.parameter.payment_type);
rowData.push(e.parameter.payment_status);
rowData.push(e.parameter.payer_email);
rowData.push(e.parameter.item_name1);
rowData.push(e.parameter.item_number1);
rowData.push(e.parameter.quantity);
rowData.push(e.parameter.first_name);
rowData.push(e.parameter.last_name);
rowData.push(e.parameter.address_street);
rowData.push(e.parameter.address_city);
rowData.push(e.parameter.address_state);
rowData.push(e.parameter.address_zip);
sheet.appendRow(rowData);
}
The above seems to work great and what the next step and I'm trying to do is take the data from a few of the cells in my google sheet where this script is working and use that in another script where an email with a link or attachment to the digital download images they purchased. I need to extract the first name, last name, payer email, and a variation of the itemname1 from above function and send the email automatically. I've set up the google sheet with the IPN information above and have added a last column 'P' where the link to the image will be located online using data from itemname1 as mentioned. The next step would be to use something like the function below using my data, but I'm having a super difficult time. I need to tweak the below function to work with my data. Is that possible? I'm not having any luck and it's all so close at this point. Anyone out there now how to do this? Can you point me in the right direction?
Something like this is what I was thinking would work for me, but I'm not sure how to tweak it to do the job I need:
// 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 sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
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, 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 = 'Sending emails from a Spreadsheet';
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();
}
}
}
My problem is that I haven't been able to put all the data together and make it work yet. Any help?

How can I add some bcc addresses to this script and not send duplicates?

I have a perfect working script that substitutes a name for an email address and then sends that address an email. I only included the email part that's broken from adding bcc.
I need to add several bcc recipients to it. But when I add them, the script keeps on sending, and enters "EMAIL_SENT" in a column and keeps on going down the column through all the blank rows like this. The script stops at the 1st blank row until I add a bcc. How can I add a bcc recipient to this and not send duplicate emails?
I added the argument for cc / bcc with a list of two emails and this makes it send duplicates.
/* Sends non-duplicate emails with data from the current spreadsheet.
*/
function SendEmail() {
//if ()
var esheet = SpreadsheetApp.getActiveSheet();
var EMAIL_SENT = 'EMAIL_SENT';
var startRow = 2; // First row of data to process
var numRows = 1000; // Number of rows to process
// Fetch the range of cells A4:C100
var dataRange = esheet.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 = 'You have a new message in the message center.';
MailApp.sendEmail(emailAddress, subject, message, {
htmlBody: message,
cc: 'boss#company.com',
bcc: 'customers#home.com'
});
esheet.getRange(startRow + i, 3).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
// [END apps_script_gmail_send_emails_2]
I expect this to send an email and stop sending when it gets to a blank row. Instead it adds EMAIL_SENT all the way down the sheet row by row. This gets stuck in a never ending loop. It works perfect unless I add the BCC Part and I need to do that today.

How do I reduce the "computer time" that my Google Apps Script is using?

I followed Hugo Fierro's tutorial on adding a Google Apps Script to send emails from Google Sheets. The tut is at https://developers.google.com/apps-script/articles/sending_emails.
I customised the script:
1) I replaced the "MailApp.sendEmail" API with "GmailApp.sendEmail" because I was getting authentication errors and the emails were not sending. The Gmail API has worked fine.
2) I added an option to send a PDF attachment with each mail using "DriveApp.getFileById".
3) I added a second condition to the IF statement to check that the PDF document is available before sending (by referencing a column in the sheet).
The problem is that if the script references only 5 rows, then it processes in under 30 seconds. When I try to process 10 rows or more, the processing time goes up significantly.
I replaced "sheet.getRange" with "sheet.getLastRow()" in an attempt to reduce how many rows the script is referencing.
var READY = 'READY';
var SENT = 'SENT';
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Email'); // Get the active spreadsheet, then get the "Email" sheet
var startRow = 2; // Select data row to start at
var endRow = sheet.getLastRow(); // Get the last row in the sheet
var data = sheet.getRange(startRow, 1, endRow, 6).getValues(); // Get the range of cells, then get the values
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var email = row[0]; // Column 1
var subject = row[1]; // Column 2
var message = row[2]; // Column 3
var attachment = DriveApp.getFileById(row[3]); // Returns the attachment file ID
var emailReady = row[4]; // Column 5
var emailSent = row[5]; // Column 6
var name = 'VFISA'; // Set "from" name in email
var bcc = 'myaddress#gmail.com'; // Blind carbon copy this email address
if (emailReady==READY && emailSent!==SENT) { // Prevents sending duplicates, waits for attachment cell to confirm available
GmailApp.sendEmail(email, subject, message,{
name: name,
bcc: bcc,
htmlBody: message,
attachments: attachment
});
sheet.getRange(startRow + i, 6).setValue(SENT); // Set the cell in column F to "SENT"
SpreadsheetApp.flush(); // Make sure the cell is updated right away in case the script is interrupted
}
}
}
I expected the script to run much faster. The error I get is "Service using too much computer time for one day". When I reference 20 rows it takes up to 4 minutes to run.
DriveApp.getFileById was causing each row to take about 5 seconds to execute. I removed this and now the entire script executes in under 1 second.
Instead of adding the PDF as an attachment, I used an inline link based on the file's ID (based on Alan Wells' suggestion).

Google Spreadsheets Script to send e-mails & keep count of total e-mails sent

I'm still learning the ropes here & was hoping somebody could kindly suggest the best way of going about this (I have searched for a solution but to no success!):
I have very simple spreadsheet:
Column A: e-mail addresses; Column B: messages to send. (Column A is generated using a formula which grabs a few e-mail addresses from a longer list of addresses in Sheet2.)
Sheet2 contains a 'master' list of all the e-mail addresses.- Column A: Name; Column B: e-mail addressess
I am using the code below as a starting point. It send e-mails to the addresses in Sheet1, and marks the cells in Column C with "EMAIL_SENT" whenever the e-mail is sent (or rather when the script is done processing that row).
I'd like to keep count of the total number of e-mails sent to each person in column C of Sheet2, however I don't know what the best way to approach this would be, or if I'm honest, where to start!
function sendEmails() {
var sheet = SpreadsheetApp.getSheetByName('Sheet1');
var EMAIL_SENT = "EMAIL_SENT";
var startRow = 1; // First row of data to process
var dataRange = sheet.getDataRange()
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 = "Sending emails from a Spreadsheet";
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();
}
}
}
So as mentioned, I'd like to keep count for each person in Sheet2, because it contains everyones e-mail addresses (whereas Sheet1 only has a handful of these and this list will change daily).
Can anyone please shed some light on this? Any suggestions would be very much appreciated.
Many thanks for looking.
Step 1: Find the row in Sheet2 where that email is located.
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
var numRows = sheet2.getDataRange().getNumRows();
var emailList = sheet2.getRange(1,2,numRows,1).getValues();
var emailRow = -1;
for (var j=0; j<numRows; j++) {
if (emailList[j][0]==WHATEVER_EMAIL_YOU_ARE_LOOKING_FOR) {
emailRow = j;
break;
}
}
if (emailRow==-1) { /*ERROR! Couldn't find email.*/ }
Step 2: Get the old count of emails.
var oldValue = sheet2.getRange(emailRow+1,3).getValue();
Step 3: Write in the new value + 1.
sheet2.getRange(emailRow+1,3).setValue(oldValue+1);
Note: emailRow is zero-based, while getRange() is one-based.