Email multiple cells to recipient instead of one email per cell using Apps Script - email

Currently I'm working on a script that checks values of one column and based on that send email containing information from another column. Everything works perfectly except one thing - it send one email per value and I'd like to send all the values in one email. Can someone please help with the issue ?
const helpsheet = SpreadsheetApp.openById("ID").getSheetByName('Sheet');
const date = helpsheet.getRange(1,10).getValue();
const ss = SpreadsheetApp.openById("ID2");
const sh = ss.getSheetByName('Sheet2');
const data = sh.getRange('A2:c'+sh.getLastRow()).getValues();
var recipients = 'EMAIL#EMAIL';
var subject = 'SUBJECT';
data.forEach(r=>{
let overdueValue = r[2];
if (overdueValue > date)
{
let path = r[0];
MailApp.sendEmail({
to: recipients,
subject: subject,
htmlBody: 'Hi guys ' + path +'!<br><br>Best regards,'
});
}
});
} ```

Of course I can't test this because 1st I don't want a bunch of emails to myself and 2nd I don't have a data set that matches your data, but I'm pretty sure this will do what you want. What I do is build an array of rows that pass the sniff test using the Array push method below. Then when I have all the rows that pass I send one email.
I have edited this post to include functions to create an html table.
function test() {
try {
const helpsheet = SpreadsheetApp.openById("ID").getSheetByName('Sheet');
const date = helpsheet.getRange(1,10).getValue();
const ss = SpreadsheetApp.openById("ID2");
const sh = ss.getSheetByName('Sheet2');
const data = sh.getRange('A2:c'+sh.getLastRow()).getValues();
var pre = "Hello";
var post = "Best regards";
var recipients = 'EMAIL#EMAIL';
var subject = 'SUBJECT';
var passed = [];
data.forEach( r => {
let overdueValue = r[2];
if (overdueValue > date) {
passed.push(r);
}
});
if( passed.length > 0 ) { // maybe nothing passed the test
var html = createHTMLfile(true);
html = html.concat("<p>"+pre+"</p>");
html = html.concat(createTable(passed));
html = html.concat(createHTMLfile());
html = html.concat("<p>"+post+"</p>");
MailApp.sendEmail( {
to: email,
subject: subject,
htmlBody: html });
};
}
}
catch(err) {
console.log(err);
}
}
I have added the additional functions to create the table. You are welcome to play with the <style>s.
function createHTMLfile(pre) {
if( pre ) {
return "<html><head><style>table, td { border: thin solid black; border-collapse:collapse; text-align:center }</style></head><body>";
}
else {
return "</body></html>";
}
}
function createTable(data) {
try {
var width = 600/data[0].length;
var table = "<table>";
function addCell(value) {
table = table.concat("<td style=width:"+width+"px>");
table = table.concat(value.toString());
table = table.concat("</td>");
}
function addRow(row) {
table = table.concat("<tr>");
row.forEach( addCell );
table = table.concat("</tr>");
}
data.forEach( addRow )
table = table.concat("</table>");
return table;
}
catch(err) {
console.log(err);
}
}

Related

Pulling Gmail "from:mailer-damon" and "from:postmaster" email data into google sheets?

I came across the code below in an article. I tried to modify it (q: "from:mailer-daemon OR from:postmaster",) so that the code can pull from not only mailer-daemon, but also postmaster emails. However, it handled the data differently for postmaster emails (postmaster recipient emails were put into the "Bounce Reason" column along with the reason). I'd also like for it to pull from a label I've created in Gmail called "Delete from CMMC List", but I'm unsure how to do that.
The column names that data is being separated into are as follows:
Bounce Date
Email Recipient
Error Status
Bounce Reason
Gmail Link
Original code that needs modification:
/*
* Gmail Bounce Report
* u/labnol Feb 12, 2020
* Written by Amit Agarwal
* email: amit#labnol.org
* twitter: u/labnol
* web: www.labnol.org
*/
const toast_ = e => SpreadsheetApp.getActiveSpreadsheet().toast(e);
const parseMessage_ = messageId => {
const message = GmailApp.getMessageById(messageId);
const body = message.getPlainBody();
const [, failAction] = body.match(/^Action:\s*(.+)/m) || [];
if (failAction === "failed") {
const emailAddress = message.getHeader("X-Failed-Recipients");
const [, errorStatus] = body.match(/^Status:\s*([.\d]+)/m) || [];
const [, , bounceReason] =
body.match(/^Diagnostic-Code:\s*(.+)\s*;\s*(.+)/m) || [];
if (errorStatus && bounceReason) {
return [
message.getDate(),
emailAddress,
errorStatus,
bounceReason.replace(/\s*(Please|Learn|See).+$/, ""),
`=HYPERLINK("${message.getThread().getPermalink()}";"View")`
];
}
}
return false;
};
const writeBouncedEmails_ = (data = []) => {
if (data.length > 0) {
toast_("Writing data to Google Sheet..");
const sheet = SpreadsheetApp.getActiveSheet();
sheet
.getRange(3, 1, sheet.getLastRow(), sheet.getLastColumn())
.clearContent();
sheet.getRange(3, 1, data.length, data[0].length).setValues(data);
SpreadsheetApp.flush();
toast_("Bounce Report is ready!");
showCredit_();
}
};
const findBouncedEmails_ = () => {
try {
const rows = [];
const { messages = [] } = Gmail.Users.Messages.list("me", {
q: "from:mailer-daemon",
maxResults: 200
});
if (messages.length === 0) {
toast_("No bounced emails found in your mailbox!");
return;
}
toast_("Working..");
for (let m = 0; m < messages.length; m += 1) {
const bounceData = parseMessage_(messages[m].id);
if (bounceData) {
rows.push(bounceData);
}
if (rows.length % 10 === 0) {
toast_(`${rows.length} bounced emails found so far..`);
}
}
writeBouncedEmails_(rows);
} catch (error) {
toast_(error.toString());
}
};
const onOpen = e => {
SpreadsheetApp.getUi()
.createMenu("🕵🏻‍♂️ Bounced Emails")
.addItem("Run Report", "findBouncedEmails_")
.addSeparator()
.addItem("Credits", "showCredit_")
.addToUi();
};
const showCredit_ = () => {
const template = HtmlService.createHtmlOutputFromFile("help");
const html = template
.setTitle("Bounce Report for Gmail")
.setWidth(460)
.setHeight(225);
SpreadsheetApp.getActiveSpreadsheet().show(html);
}

Download all user aliases to a Google spreadsheet

I am attempting to list all user aliases in our network. However, I am having a bit of trouble. I'm working from a bit of canned code here. I know the alias is an array but accessing it per user then listing just the aliases has me seeing double. Any help or tips is much appreciated!
function AliasDomainUsersList() {
var users_alias = [];
var options_alias = {
domain: "northstarmoving.com", // Google Apps domain name
customer: "my_customer",
maxResults: 100,
projection: "full", // Fetch basic details of users
viewType: "domain_public",
orderBy: "email" // Sort results by users
}
do {
var response = AdminDirectory.Users.list(options_alias);
response.users.forEach(function(user) {
users_alias.push([user.name.fullName, user.primaryEmail]);
});
// For domains with many users, the results are paged
if (response.nextPageToken) {
options_alias.pageToken = response.nextPageToken;
}
} while (response.nextPageToken);
// Insert data in a spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Users-Aliases") || ss.insertSheet("Users-Aliases", 1);
sheet.getRange(1,1,users_alias.length, users_alias[0].length).setValues(users_alias);
}
I think something like this might work. I haven't tested this because I'm the only person in my business account.
function AliasDomainUsersList() {
var users_alias = [];
var options_alias = {
domain: "northstarmoving.com", // Google Apps domain name
customer: "my_customer",
maxResults: 100,
projection: "full", // Fetch basic details of users
viewType: "domain_public",
orderBy: "email" // Sort results by users
}
do {
var response = AdminDirectory.Users.list(options_alias);
for(var i=0;i<response.users.length;i++) {//you will probably want to do this your way.
users_alias.push([response.users[i].name,response.users[i].primaryEmail]);
}
// For domains with many users, the results are paged
if (response.nextPageToken) {
options_alias.pageToken = response.nextPageToken;
}
} while (response.nextPageToken);
// Insert data in a spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Users-Aliases") || ss.insertSheet("Users-Aliases", 1);
sheet.getRange(1,1,users_alias.length, users_alias[0].length).setValues(users_alias);
var sheet2=ss.getSheetByName('AnotherSheet')
var rg2=sheet2.getRange(1,1,users_alias.length,1);
var vA2=rg2.getValues();
for(var i=0;i<vA2.length;i++) {
vA2[i][0]=users_alias[i][1];
}
rg2.setValues(vA2);
}
Managed to work out the solution (with some help). Here it is:
function getDomainUsersList() {
var users = [];
var options = {
domain: "northstarmoving.com", // Google Apps domain name
customer: "my_customer",
maxResults: 500,
projection: "full", // Fetch details of users
viewType: "domain_public",
orderBy: "email" // Sort results by users
}
do {
var response = AdminDirectory.Users.list(options);
response.users.forEach(function(user) {
users.push([user.name.fullName, user.primaryEmail]);
});
// For domains with many users, the results are paged
if (response.nextPageToken) {
options.pageToken = response.nextPageToken;
}
} while (response.nextPageToken);
// Insert data in a spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Users") || ss.insertSheet("Users", 1);
sheet.getRange(1,1,users.length, users[0].length).setValues(users);
}

Send multiple attachments using DriveApp.getFileById in Google Apps Script

I am trying to get a script running that takes multiple file IDs from a Google Sheet and attaches them to an email. I cannot get multiple files to be attached using DriveApp.getFileById.
The script runs and fires off an email, but with no attachments.
function createAndSendDocument(values) {
// Get the email address of the active user
var email = Session.getActiveUser().getEmail();
// Get the name of the document to use as an email subject line.
var subject = 'New Paperwork';
//Let's add the attachments variables
var attachmentstring = values["Which documents do you want to attach?"];
var array = attachmentstring.toString().split(",");
var blobs = [];
var x = 0;
for (var i = 0; i < array.length; i++) {
//check if even
if (i % 2 === 0) {
blobs[x] = array[i];
x++;
}
}
// Append a new string to the "url" variable to use as an email body.
var body = 'your doc: ' + blobs[0] + blobs[1] + array[0] + array[1] + "length:" + array.length;
// Send yourself an email with a link to the document.
GmailApp.sendEmail(email, subject, body, {attachments: blobs});
}
I edited the original post to include the snippet of code. Here is the output of the blobs and array.
undefinedundefinedW-4 2019.pdf1YjQqFNze8VX0L6wZ9O3Y9AJNznR8jfxqlength:4
This code worked:
function createAndSendDocument(values) {
// Get the email address of the active user
var email = Session.getActiveUser().getEmail();
// email subject line.
var subject = 'New Paperwork';
// add the attachments variables
var attachmentstring = values["Which documents do you want to attach?"];
var array = attachmentstring.toString().split(",");
var blobs = [];
var x = 0;
for (var i = 0; i < array.length; i++) {
//check if even
if (i % 2 === 0) {
}
else
{
blobs[x] = DriveApp.getFileById(array[i]).getBlob();
x++;
}
}
// an email body.
var body = 'Hello';
// Send an email with attachments
GmailApp.sendEmail(email, subject, body, {attachments: blobs});
}

Email a reminder based on the status of a cell Google apps script

I am attempting to set a simple reminder email to a technician to remind when a routine service is due. I have a 2d array and code that works, but it only sends 1 email, which is the lowest row.
I'm kinda new to this, but I would like it to run through each row and send a reminder for every overdue.
Any help appreciated.
This is what I have now:
function Email_Reminder()
{;
var sheet = SpreadsheetApp.getActiveSheet();
statusArray = sheet.getDataRange().getValues();
status = "overdue";
for (i=3;i < statusArray.length;i++){
if (status == statusArray[i][6]) {
var customer = statusArray[i][0];
}
}
var email = "djens12#gmail.com"
var subject = "Reminder";
var body = "This is a reminder that the service is overdue for " +customer+ "";
MailApp.sendEmail(email,subject,body,{NoReply : true});
}
thanks
Just move your MailApp.sendEmail() inside your for loop
function Email_Reminder()
{;
var sheet = SpreadsheetApp.getActiveSheet();
statusArray = sheet.getDataRange().getValues();
status = "overdue";
var email = "djens12#gmail.com"
var subject = "Reminder";
for (i=3;i < statusArray.length;i++){
if (status == statusArray[i][6]) {
var customer = statusArray[i][0];
var body = "This is a reminder that the service is overdue for " +customer+ "";
MailApp.sendEmail(email,subject,body,{NoReply : true});
}
}
}

import private google fusion table to google docs spreadsheet

I want to build a chart to google fusion table. I know there is an option to do it with fusion table but I need to do that using google spreadsheet.
How do I import a private fusion table to a spreadsheet?
function getdata(authToken) {
query = encodeURIComponent("SELECT * FROM tableid");
var URL = "http://www.google.com/fusiontables/api/query?sql=" + query;
var response = UrlFetchApp.fetch(URL, {
method: "get",
headers: {
"Authorization": "GoogleLogin auth=" + authToken,
}
});
return response.getContentText();
}
The code above gives me the table headers only.
Don't set each cell individually as in the example below unless you need to process each bit of data. Using this is about 10x faster:
var rows = o.length;
var columns = o[0].length;
cell.offset(<startrow>, <startcolumn>, rows, columns).setValues(o);
After a deep research, finally i figured it out after a deep search and reading here.
This is how it looks for the code google docs spreadsheet app script:
function onOpen()
{
var tableID = '00000' // Add the table ID of the fusion table here
var email = UserProperties.getProperty('email');
var password = UserProperties.getProperty('password');
if (email === null || password === null) {
email = Browser.inputBox('Enter email');
password = Browser.inputBox('Enter password');
UserProperties.setProperty('email',email);
UserProperties.setProperty('password', password);
} else {
email = UserProperties.getProperty('email');
password = UserProperties.getProperty('password');
}
var authToken = getGAauthenticationToken(email,password);
query = encodeURIComponent("SELECT * FROM tableID");
var URL = "http://www.google.com/fusiontables/api/query?sql=" + query;
var response = UrlFetchApp.fetch(URL, {
method: "get",
headers: {
"Authorization": "GoogleLogin auth=" + authToken,
}
});
var tableData = response.getContentText();
var o = Utilities.parseCsv(response.getContentText());
var doc = SpreadsheetApp.getActiveSpreadsheet();
var cell = doc.getRange('a1');
var index = 0;
for (var i in o) {
var row = o[i];
var col = 0;
for (var j in row) {
cell.offset(index, col).setValue(row[j]);
col++;
}
index++;
}
}
function getGAauthenticationToken(email, password) {
password = encodeURIComponent(password);
var response = UrlFetchApp.fetch("https://www.google.com/accounts/ClientLogin", {
method: "post",
payload: "accountType=GOOGLE&Email=" + email + "&Passwd=" + password + "&service=fusiontables&Source=testing"
});
var responseStr = response.getContentText();
responseStr = responseStr.slice(responseStr.search("Auth=") + 5, responseStr.length);
responseStr = responseStr.replace(/\n/g, "");
return responseStr;
}
After that you can do whatever you want in the spreadsheet.
BTW, I still think there is a simple way to import a private table into a spreadsheet automaticly.