I am using this script to send reminder emails. It works when I run it manually, but when I try to run it on a trigger, it fails.
var EMAIL_SENT = 'EMAIL_SENT';
function sendEmail() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Job Checkup Tool');
var startRow = 4; // First row of data to process
var numRows = 13; // 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 = 'Job Checkup Reminder';
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();
}
}
}
The problem appears to be a result of the script finding no email address in column 1.
When I run it manually, though it has an error, it will successfully send the emails even if there isn't an email value in column 1.
When the trigger runs it, it shows the same error
Exception: Failed to send email: no recipient
but doesn't send any emails.
If I adjust the range to focus only on rows with an email address in column 1, it runs great manually and via the trigger.
Is there a good way to request the script to send the email IF there is an email present within column 1 but then ignore the other rows that don't have an email yet?
Replace
if (emailSent !== EMAIL_SENT) {
by
if (emailAddress !== '' && emailSent !== EMAIL_SENT) {
Related
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;
My goal is to create email drafts automatically from a Google Sheets list. Everything works mostly, the only problem I am having is that the message in the email just says [object Object].
The subject is fine, the email address is fine, and the break to keep it from sending to the same person again is fine.
I am not sure what is wrong.... but I am guessing it starts at //Build the email message.
Any suggestions?
I have the following:
var EMAIL_DRAFTED = "EMAIL DRAFTED";
function draftPastDueEmails() {
var sheet = SpreadsheetApp.getActiveSheet(); // Use data from the active sheet
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow() - 1; // Number of rows to process
var lastColumn = sheet.getLastColumn(); // Last column
var dataRange = sheet.getRange(startRow, 1, numRows, lastColumn) // Fetch the data range of the active sheet
var data = dataRange.getValues(); // Fetch values for each row in the range
// Work through each row in the spreadsheet
for (var i = 0; i < data.length; ++i) {
var row = data[i];
// Assign each row a variable
var clientName = row[12]; // Client name
var clientEmail = row[14]; // Client email
var reference = row[1]; // Account Reference
var invNum = row[0]; // Invoice number
var emailStatus = row[20]; // Email Status
// Prevent from drafing duplicates and from drafting emails without a recipient
if (emailStatus !== EMAIL_DRAFTED && clientEmail) {
// Build the email message
var emailBody = '<p>Hello ' +clientName+ ',</p>';
emailBody += '<p>I hope all is well.</p>';
emailBody += '<p>I noticed that invoice <strong>' +invNum+ '</strong> is currently past due.</p>';
emailBody += '<p>Could you please take a moment to check your records to see if a payment has been made and provide a receipt to allow me to track it in my system.</p>';
emailBody += '<p>If no payment has been made for whatever reason, please do so as soon as possible so I can post it to your account.</p>';
emailBody += '<p>Please let me know if you have any questions.</p>';
emailBody += '<p>Best,</p>';
// Create the email draft
GmailApp.createDraft(
clientEmail, // Recipient
'Past due account - '+reference+ // Subject
'',
{
htmlBody: emailBody // Options: Body (HTML)
}
);
sheet.getRange(startRow + i, lastColumn).setValue(EMAIL_DRAFTED); // Update the last column with "EMAIL_DRAFTED"
SpreadsheetApp.flush(); // Make sure the last cell is updated right away
}
}
}
It looks like the problem is here:
// Create the email draft
GmailApp.createDraft(
clientEmail, // Recipient
'Past due account - '+reference+ // Subject
'',
{
htmlBody: emailBody // Options: Body (HTML)
}
);
The method is expecting 3 strings -- a recipient, subject and a body -- followed by options with your "htmlBody" parameter. The code above only provides a recipient and a subject. Try this instead:
// Create the email draft
GmailApp.createDraft(
clientEmail, // Recipient
'Past due account - '+reference, // Subject
'', // Plaintext body
{
htmlBody: emailBody // Options: Body (HTML)
}
);
In using this tutorial script from: https://developers.google.com/apps-script/articles/sending_emails
I am new to apps script and have been searching the forums trying to figure this out...
I'm trying to use another column in the spreadsheet to dynamically enter the salutation in the message. I thought it would be a formula like this:
="Dear "E2, + "Our 2018 Catalog is Coming Soon! Would you like a copy? " But, then I get the error that -ADD parameter1 is text and it is looking for numbers-, (even though I found it in another help area to use the quotes to separate the cell references).
So my questions:
1.Is it possible to make dynamic changes to the message in this script? Or do I need another script in the message column to do this?
2.If I am running more than one script on the spreadsheet and connected form do I need separate script files or just separate blocks on the same file
Thank you!
Adding a separate salutation to an email script
Here's the script for that tutorial:
// 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 = 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();
}
}
}
I believe you wish to have a separate salutation which is at the beginning of the message portion. It appears that you also wish to use column 5 for that data.
So if that's the case then your message would be something like this:
var message = Utilities.formatString('Dear %s\n%s',row[4],row[1]); Reference
This could also be accomplished this way:
var message = 'Dear ' + row[4] + '\n' + row[1];Reference
In either case you would put a name in column 5 and the rest of your message in column2. If you wan't to use html in your email replace the '\n' (line feed) with '<br />' (line break);
The message starts with the saluation in row[4] (column 5) and the rest of the message comes from row[1] according to the tutorial which is column 2.
The data from a getValues() command is returned in an array. Arrays index from zero where as columns in the spreadsheet begin at 1. Reference
If I misinterpreted your question please ask for further assistance in comments below. I'll be glad to help you.
I'm following the Google Scripts tutorials on how to send emails from a google sheet.
The code works fine and I do receive an email when I run it. However, when I check my inbox, instead of the header showing my name in the preview, it shows the full email address.
Here's the code from the tutorial:
function sendEmails() {
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, 2)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[0]; // First column
var message = row[1]; // Second column
var subject = "Sending emails from a Spreadsheet";
MailApp.sendEmail(emailAddress, subject, message);
}
}
Is there any way I can set it to be my name instead of it being my full email address?
How about following modification for your script?
From :
MailApp.sendEmail(emailAddress, subject, message);
To :
MailApp.sendEmail(emailAddress, subject, message, {name: '### Your name ###'});
If this was not helpful for you, I'm sorry.
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.