Create and pop up a new email using data from spreadsheet - google-apps-script

I have spreadsheet in `Google-drive' that contains information like below:
I need to add a button to each row (suppose that we have more data) and If I click it will pop up an html with a new email that contains info from that spreadsheet and that specific row.
Currently, I've created the following gs file in Apps Script the following script that creates a draft email. However, I want to create and view the new email in order to add more info to the message and then send it.
/**
* 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:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 9);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i in data) {
var row = data[i];
var emailAddress = row[7]; // First column
var message = row[8]; // Second column
var subject = row[1]+" " + row[6]+ " " + row[1];//'Sending emails from a Spreadsheet';
GmailApp.createDraft(emailAddress, subject, message);
}
}

I found a solution thanks to this solution.
I edited my gs file in Apps Script to have the following script:
/**
* Sends emails with data from the current spreadsheet.
*/
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var row = sheet.getActiveCell().getRow();
var column = 1;//= sheet.getActiveCell().getColumn();
var dataRange = sheet.getRange(row, 1, column, 10);
var data = dataRange.getValues();
var row = data[0];//[i];
var emailAddress = row[7]; // First column
var message = row[8]; // Second column
var subject = row[1]+" " + row[6]+ " " + row[2];//'Sending emails from a Spreadsheet';
GmailApp.createDraft(emailAddress, subject, message);
}
function onOpen(e) {
SpreadsheetApp.getUi()
.createMenu("Send email")
.addItem('Generate Draft Email', 'sendEmails')
.addToUi();
}
Now, in my menu in my spreadsheet I have Send Email tab like below:
When I go to a selected row, I click the submenu Generate Draft Email from Send Email and a new email is generated in my Gmail draft emails.

Related

Google Sheets Script - Not Recognizing Sheet

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.

I am trying to send Google Drive Attachments to different email addresses using a script but struggling to make it work

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.

How to get Google Drive PDF files with "name contains info in cell D1:D from Spreadsheet" and send them as emails to each contact in column A

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.

Attaching Google Sheet to emails from Gmail automatically using G Script

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]});
}
}

How to get an email sent from only the last row of my form

I am very new to coding and I can't figuer out what I am doing wrong. I need 1 email sent from the last entry in my form. So as the students submit their pre-test they get an email that contains the result of their pre-test.
This is what my code looks like:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 3; // First row of data to process
var numRows = 1; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 3, 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[1]; // Second column
var message = row[2]; // Third column
var subject = "Résultat de formatif";
// This logs the value in the very last cell of this sheet
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var lastCell = sheet.getRange(lastRow, lastColumn);
Logger.log(lastCell.getValue());
MailApp.sendEmail(emailAddress, subject, message);
}
}
I do that by:
adding a separate column "STATUS" to the sheet
in your email sending function iterate over rows and act only on rows with "STATUS" being blank
after successfully sending email for a row, put something to the "STATUS" column
Please review the event object documentation.
You can install a "trigger" to automatically run your script on every form submission. Because this is triggered per submission, you don't need to worry about trying to find the last row or if the email had already been sent.
function sendEmails(formResponse) {
var answers = formResponse.values;
var emailAddress = answers[1]; // Second column
var message = answers[2]; // Third column
var subject = "Résultat de formatif";
// This logs the value in the very last cell of this sheet
var range = formResponse.range;
var row = range.getRow();
var column = range.getLastColumn();
try {
MailApp.sendEmail(emailAddress, subject, message);
} catch (e) {
console.error("Did not send email to " + emailAddress + ". See error: " + e);
range.getSheet().getRange(row, column+1).setValue("EMAIL NOT SENT");
return;
}
range.getSheet().getRange(row, column+1).setValue("EMAIL SENT");
}