I found a G Script that works for sending an email to hundreds of addresses, based on an excel file with the name (which I can convert into Sheets if necessary).
I want to be able to add an attachment (which is currently an excel file, but can easily be converted into Sheets) to each email that is sent. The attachment is the same for each email.
The below script works for sending the emails, but I can't find the right way to add an attachment to each email (Note: line 17 is where I'm getting the error code).
I've tried a few different versions based on other similar strings on this site - but I can't get it to work with my situation, or maybe I don't understand how to structure the syntax accordingly.
/**
* Sends emails with data from the current spreadsheet.
*/
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 1; // Number of rows to process
// Fetch the range of cells A2:B2
var dataRange = sheet.getRange(startRow, 1, numRows, 1);
// 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'
var file = Drive.Files.get('test123/xlsx');
MailApp.sendEmail(emailAddress, subject, message, {attachments:
[file]});
}
}
ReferenceError: "Drive" is not defined. (line 17, file "Code")
"Drive" is the Advanced Drive API.In order to use the Drive advanced api you need to enable that api. But you really don't need the advanced api here.
Is your file in drive?
If so try this instead:
var file = DriveApp.getFileById("XXXXXXXXXXX");
the "xxx" should be the drive id.
According to the reference documentation, it looks like the class you're looking for is DriveApp.
/**
* Sends emails with data from the current spreadsheet.
*/
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 1; // Number of rows to process
// Fetch the range of cells A2:B2
var dataRange = sheet.getRange(startRow, 1, numRows, 1);
// 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';
var file = DriveApp.getFileById('test123/xlsx');
MailApp.sendEmail(emailAddress, subject, message, {attachments:
[file]});
}
}
Related
I've a Google Sheet.
I went to Tools > Script Editor.
I want to send an email when there are new rows in the sheet.
Here is my script below.
When debugging the ss variable seems to be set but is null.
So when I get to getSheetByName it is also null.
I'm not sure why it isn't getting the sheet.
// 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() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Pricing Changes');
var startRow = 2; // First row of data to process
var numRows = 0; // Number of rows to process
numrows = sheet.getLastRow();
// 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 vdate = row[0]; // First column
var vasin = row[1]; // Second column
var vcurrentprice = row[2]; // Third column
var vnewprice = row[3]; // Third column
var vremarks = row[4]; // Third column
var emailsent = row[5]; // Third column
var message = vdate & "-" & vasin & "-" & vcurrentprice & "-" & vnewprice & "-" & vremarks;
if (emailSent !== EMAIL_SENT) { // Prevents sending duplicates
var subject = 'Sending emails from a Spreadsheet';
MailApp.sendEmail(emailAddress, "New Price Changes", 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();
}
}
}
Note that I have set it up as a File as it was previously set up as "Code" but I thought perhaps that was the issue. (I'm not able to embed the image so hopefully stack will put the correct image link.)
App Script UI Screen Shot
Since you mentioned that both getActive() and getActiveSpreadsheet() returns a null. The last option you have to get the Spreadsheet object is to use either of the following:
1. openById(id)
Opens the spreadsheet with the given ID
A spreadsheet ID can be extracted from its URL. For example, the spreadsheet ID in the URL https://docs.google.com/spreadsheets/d/abc1234567/edit#gid=0 is "abc1234567".
2. openByUrl(url)
Opens the spreadsheet with the given URL. Throws a scripting exception if the URL does not exist or the user does not have permission to access it.
Stack overflowers!
I have a problem with my Sendemail Script, which is sending the same message for 8 times (really annoying, isn't it?) to each mail address. (It has been working fine until today though, I send remainders to five people daily; and my google sheet has two columns, one is for email address and the other is the message)
My code looks like this:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 5; // Number of rows to process
// Fetch the range of cells A2:B6
var dataRange = sheet.getRange(startRow, 1, numRows, 5);
// 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 message = row[1]; // Second column
var subject = 'ATTENTION!!!!!!';
MailApp.sendEmail(emailAddress, subject, message);
}
}
How can I solve this annoying problem? (I am not a developer; I am just a learner who can use internet sources very well; So, I don't understand scripts much and still can edit or change it a bit.)
There is currently a bug with time-driven triggers
As a consequence, the trigger might fire multiple times - more frequent than you specify.
You can "star" the issue on Google's Issue Tracker to indicate that you are also concerned.
In the meantime, as a workaround:
Use Script Properties to save the last execution time
Implement an if statement at the beginning of your code that executes the rest of the code only if the last execution time (retrieved from the script properties) is not less than the specified interval
Sample:
function sendEmails() {
if(!PropertiesService.getScriptProperties().getProperty("lastExecution")){
PropertiesService.getScriptProperties().setProperty("lastExecution", new Date().getTime());
}
var lastExecution = PropertiesService.getScriptProperties().getProperty("lastExecution");
var now = new Date().getTime();
var oneDay = 1000*3600*24;
if(now-lastExecution >= oneDay){
//here the rest of you code
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 5; // Number of rows to process
// Fetch the range of cells A2:B6
var dataRange = sheet.getRange(startRow, 1, numRows, 5);
// 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 message = row[1]; // Second column
var subject = 'ATTENTION!!!!!!';
MailApp.sendEmail(emailAddress, subject, message);
PropertiesService.getScriptProperties().setProperty("lastExecution", now);
}
}
}
New to Google Scripts so I'm bumping my head on this entry level code. I want to send an email based on a specific sheet in a spreadsheet. The tab or sheet is named 'Test 2'. Currently this is my code.
/* Sends emails with data from the current spreadsheet.*/
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
var dataRange = getRange(startRow, 1, numRows, 2); // Fetch the range of cells A2:B6
var data = dataRange.getValues(); // Fetch values for each row in the Range.
for (var i in data) {
var row = data[i];
var emailAddress = row[0]; // First column
var message = row[1]; // Second column
var subject = 'THIS IS A TEST';
MailApp.sendEmail(emailAddress, subject, message);
}
}
And right now it's throwing this error.
ReferenceError: "getRange" is not defined. (line 8, file "Code")
How can I get it to run while referencing that sheet 'Test 2'?
Thanks!
You want to avoid the error of "getRange" is not defined..
You want to retrieve the values from the cell "A2:B6" of the sheet Test 2.
If my understanding is correct, how about the following modification?
From:
var dataRange = getRange(startRow, 1, numRows, 2);
To:
var dataRange = sheet.getSheetByName("Test 2").getRange("A2:B6");
Note:
In this case, at first, retrieve the sheet object of Test 2 and use the method of getRange for the sheet object.
I thought that a1Notation might be suitable for your situation.
Reference:
getSheetByName()
getRange(a1Notation)
If I misunderstood your question and this was not the direction you want, I apologize.
I am new to coding and wanted to automate sending emails with attachments. Basically what I would like to do is to send a message and Google Drive attachment to a specific email address in my spreadsheet. Each attachment (google drive link) is different for each email address and I have everything laid out on a spreadsheet.
The spreadsheet is composed of three sheets, and I want to get the info from the first sheet only (called Full Data). The structure of the columns is the following:
A1 Full Name
B1 First Name
C1 Last Name
D1 Email Address
E1 File attachment (google drive link)
F1 Date
G1 Status
H1 Message
I1 Email Sent?
I would like to send an email with a template starting with "Hello {Full Name}," and in the row below starts the message.
Here's the code I have for now:
// 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 numRows = sheet.getLastRow() - startRow + 1; // Number of rows to process
var startCol = 1;
var numCols = 4; // Number of columns to process (should include column D)
// Fetch the range of cells A2:D
var dataRange = sheet.getRange(startRow, startCol, numRows, numCols);
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[3]; // Third column
var message = row[7]; // Eigth column
var emailSent = row[8]; // Ninth column
if (emailSent !== EMAIL_SENT) { // Prevents sending duplicates
var subject = 'Sending emails from a Spreadsheet';
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 8).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
I realize that I have not set a variable for the attachment. The attachment should be taken from column E (corresponding to the row). For example, John Apple in A2 has attachment X in E2, while Mick Orange in A3 has attachment Y in E3, and so on... The range of data goes down till 130 rows but it would be great to have something that always gets the range until there is data (no matter the number of rows).
Does anyone have an idea on how to make this work?
Thanks a lot in advance!!
If I understand you correctly, your current question differs from your previous one in that:
The message body starts with "Hello {Full Name}".
You are not looking for files with the same name as in the sheet, but files that have a certain URL.
The columns to fetch the data from are not the same.
Taking all this into account, I reworked the solution I proposed in your previous question so that it does what you pretend now (read inline comments to see what the code is doing, step by step):
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Full Data");
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow() - startRow + 1; // Number of rows to process
var startCol = 1;
var numCols = 9; // Number of columns to process (should include column D)
// Fetch the range of cells A2:D
var dataRange = sheet.getRange(startRow, startCol, numRows, numCols);
// 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[3];
var fullname = row[0];
var messageBody = row[7];
var message = "Hello ".concat(fullname, "\n", messageBody); // Creating message body
var emailSent = row[8];
var fileURL = row[4];
var fileId = fileURL.match(/[-\w]{25,}/); // Extracts file id from file url
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = "Sending emails from a Spreadsheet";
var file = DriveApp.getFileById(fileId);
MailApp.sendEmail(emailAddress, subject, message, {
attachments: [file], // No need to use getAs if your file is already a PDF
name: 'Custom email Team'
});
sheet.getRange(startRow + i, 9).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
DriveApp does not have an getFileByUrl method, so to get the file, the code first extracts the file id from the url using regex and then calls getFileById.
Let me know if that works for you.
Disclaimer: I am new to programming so please bear with me :)
I am trying to send emails with a PDF file attachment to different email contacts on a Google Spreadsheet. Each attachment has to be unique to each Name by looking up that file name on google drive. Can someone help with that extra bit of code?
The code I have is currently sending emails with a custom message and a file attachment, and marking each email as sent in column C once the script ends running. However, I would like to send a different PDF attachment to each and every email address, ideally by writing some code that gets the "Investor Name" in column D, looks up the file in Google Drive that contains that name, and attaches that file to the email to be sent out.
So, I need to get the PDF file by each name in each corresponding cell, and not as written below (I believe):
var file = DriveApp.getFilesByName('SHARE CERTIFICATE #60 - JOHN APPLE.pdf');
// 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 = 250; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 250)
// 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";
var file = DriveApp.getFilesByName('SHARE CERTIFICATE #60 - JOHN APPLE.pdf');
if (file.hasNext()) {
MailApp.sendEmail(emailAddress, subject, message, {
attachments: [file.next().getAs(MimeType.PDF)],
name: 'Custom email Team'
});
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 final result I expect is to:
- Send Emails to different email addresses with a message and subject
- Attach a PDF file with file name that correspond to the Name of each email recipient
Thanks a lot in advance, this will massively help! :)
Your code is missing a small detail. Basically, you should get the data from column D when using getRange:
var numRows = sheet.getLastRow() - startRow + 1; // Number of rows to process
var startCol = 1;
var numCols = 4; // Number of columns to process (should include column D)
// Fetch the range of cells A2:D
var dataRange = sheet.getRange(startRow, startCol, numRows, numCols);
Notice that the number of rows to be retrieved doesn't have to be hardcoded. If you use getLastRow you can get the index of the last row with content, and use that to get the desired range. This way you can get exactly the number of rows you want; not more, not less.
Then, inside the loop, retrieve the value in column D, like this:
var fileName = row[3]; // Fourth column
Finally, you retrieve the file from Drive like this:
var files = DriveApp.getFilesByName(fileName);
So the full modified code could be like:
// 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 = sheet.getLastRow() - startRow + 1; // Number of rows to process
var startCol = 1;
var numCols = 4; // Number of columns to process (should include column D)
// Fetch the range of cells A2:D
var dataRange = sheet.getRange(startRow, startCol, numRows, numCols);
// 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
var fileName = row[3]; // Fourth column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = "Sending emails from a Spreadsheet";
var files = DriveApp.getFilesByName(fileName);
if (files.hasNext()) {
var file = files.next();
MailApp.sendEmail(emailAddress, subject, message, {
attachments: [file], // No need to use getAs if your file is already a PDF
name: 'Custom email Team'
});
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 have made some additional small changes to that code (for example, changing the variable file to files and then defining var file = files.next()).
I hope this is of any help to you.
Something like this will work I think:
function sendEmails() {
var ss=SpreadsheetApp.getActive();
var sheet=ss.getActiveSheet();
var logsheet=ss.getSheetByName('logSheet');//added logsheet
if(!logsheet){ss.insertSheet('logSheet');}
var startRow=3;//added one row here to accomodate subject and pdfFldrId
var dataRange = sheet.getRange(startRow, 1, sheet.getLastRow()-startRow-1,sheet.getLastColumn())
var data = dataRange.getValues();
var subject= sheet.getRange("B2").getValue();
var pdfFldrId=sheet.getRange("C2").getValue();
for (var i=0;i<data.length;++i) {
var row=data[i];
var emailAddress=row[0];
var message=row[1];
var emailSent=row[2];
var pdfName=row[3];
var files=DriveApp.getFolderById(pdfFldrId).getFilesByName(pdfName);
var n=0;
while(files.hasNext()) {
var file=files.next();
n++;
}
if(n>1){
var ts=Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "MM/dd/yyyy HH:mm:ss");
logsheet.append([ts,pdfName,'more than file with this name']);
continue;//breaks out of loop increment index and keep going
}
if(emailSent!="EMAIL_SENT") {
MailApp.sendEmail(emailAddress, subject, message, {attachments:[file]});
sheet.getRange(startRow + i, 3).setValue("EMAIL_SENT");
}
}
}
If you want to send a different image with the same email list just duplicate the sheet and change the pdfFldrId and the subject which are found in C2 and B2 and learn to keep the different images is different folders with the same filenames.