List all Labels of an email to Spreadsheet - email

My emails usually has more than one Labels assigned. I like to search emails with a specific label then list them into the spreadsheet and show all other labels also assigned to the email.
Here's what i have so far, can't figure out how to get the other labels...
function myFunction() {
var ss = SpreadsheetApp.getActiveSheet();
var threads = GmailApp.search("label:Test");
for (var i=0; i<threads.length; i++)
{
var messages = threads[i].getMessages();
for (var j=0; j<messages.length; j++)
{
var sub = messages[j].getSubject();
var from = messages[j].getFrom();
var dat = messages[j].getDate();
ss.appendRow([dat, sub, from])
}
}
}

As far as Apps Script is concerned, Gmail labels are applied to threads and not to individual messages. (There are other contexts where this isn't necessarily true, as a Web Apps post details).
So, you should use the getLabels method of the Thread object. It then makes sense to structure the output so that each row corresponds to a thread, rather than a message. This is what I did below. The script takes subject/from/date from the first message in each thread. The 4th column is the comma-separated list of labels, except the one you search for.
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
var search_label = 'Test';
var threads = GmailApp.search('label:' + search_label);
var output = [];
for (var i=0; i < threads.length; i++) {
var firstMessage = threads[i].getMessages()[0];
var sub = firstMessage.getSubject();
var from = firstMessage.getFrom();
var dat = firstMessage.getDate();
var labels = threads[i].getLabels();
var otherLabels = [];
for (var j = 0; j < labels.length; j++) {
var labelName = labels[j].getName();
if (labelName != search_label) {
otherLabels.push(labelName);
}
}
output.push([dat, sub, from, otherLabels.join(', ')]);
}
sheet.getRange(1, 1, output.length, output[0].length).setValues(output);
}
I prefer not to add one row at a time, instead gathering the double array output and inserting it all at once. Of course you can use appendRow as in your script. Then you wouldn't necessarily need a comma-separated list,
sheet.appendRow([dat, sub, from].concat(otherLabels));
would work.

Related

Send single email containing a table based on a condition to the recipients when the names are repetitive using google app script

This is the extended version of my previous question.
I want to send email once in a week to the recipients based on the status column.
Sheet Link: https://docs.google.com/spreadsheets/d/1GC59976VwB2qC-LEO2sH3o2xJaMeXfXLKdfOjRAQoiI/edit#gid=1546237372
The previous code is attached in the sheet.
From the sheet, When the Status column will be new and ongoing, a table will be generated with column Title, Link and due date and send a single email to the recipients even they are repeated.
In the sheet, For resource Anushka, Status New appeared twice and Ongoing once. The table will be like-
Anushka || New || 10/25/2022
Anushka || New || 10/25/2022
Anushka || Ongoing || 10/25/2022
And after creating it, it will send single email to each recipients though they have appeared several times.
I have done it for getting multiple emails whatever the status is with the help of another commenter from stackflow but I want to modify it and change it. The code for this one is a bit longer as I have two helper gs file, html table code and the main one. That's why I am not writing all the codes here. But in the sheet from the extension, one can see my code.
If anyone give me suggestions how to change or modify the logic, it will be appreciated.
Code
function macro(){
// get range of cell with data from A1 to any cell near having value (call data region)
var table = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet3").getRange("A1").getDataRegion();
var header=table.getValues()
var resource=header[0][1]
var status_r=header[0][3]
var due_date_r=header[0][5]
var link_r=header[0][10]
// create custom table filtered by the column having header "State" where the value match "New"
var filterTable = new TableWithHeaderHelper(table)
.getTableWhereColumn("Status").matchValueRegex(/(New)/);
// for each row matching the criteria
for(var i=0; i< filterTable.length() ; i++){
// Get cell range value at column Mail
var mail = filterTable.getWithinColumn("Email").cellAtRow(i).getValue();
// Any other value of column Target Value
var resource_col = filterTable.getWithinColumn("Resource").cellAtRow(i).getValue();
var status_col = filterTable.getWithinColumn("Status").cellAtRow(i).getValue();
var due_date_col = filterTable.getWithinColumn("Due Date").cellAtRow(i).getValue();
var link_col = filterTable.getWithinColumn("Link").cellAtRow(i).getValue();
var new_data=[[resource_col,status_col,due_date_col,link_col]]
var htmltemplate=HtmlService.createTemplateFromFile("email")
htmltemplate.resource=resource
htmltemplate.status_r=status_r
htmltemplate.due_date_r=due_date_r
htmltemplate.link_r=link_r
htmltemplate.new_data=new_data
var htmlformail=htmltemplate.evaluate().getContent()
var subjectMail = "Automation Support Services Actions Items";
var dt1 = new Date()
var dt2 = due_date_col
// get milliseconds
var t1 = dt1.getTime()
var t2 = dt2.getTime()
var diffInDays = Math.floor((t1-t2)/(24*3600*1000));
// 24*3600*1000 is milliseconds in a day
console.log(diffInDays);
// Send email
MailApp.sendEmail({
to:mail ,
subject: subjectMail,
htmlBody:htmlformail,
});
}
}```
2 loops can make the job.
// get range of cell with data from A1 to any cell near having value (call data region)
var table = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet3").getRange("A1").getDataRegion();
// init html header data
var header=table.getValues()
var resource=header[0][1]
var status_r=header[0][3]
var due_date_r=header[0][5]
var link_r=header[0][10]
var listOfEmails = [];
var tableWithHeader = new TableWithHeaderHelper(table)
// get all email
for(var i=0; i< tableWithHeader.length() ; i++){
var mail = tableWithHeader.getWithinColumn("Email").cellAtRow(i).getValue();
listOfEmails.push(mail)
}
// filter all email to get unique liste of email
var uniqueMailList = listOfEmails.filter((c, index) => {
return listOfEmails.indexOf(c) === index;
});
for(var i=0; i< uniqueMailList.length; i++){
// get mail of target i
var mail = uniqueMailList[i]
// filter table using mail of target i and status
var mailTable = new TableWithHeaderHelper(table)
.getTableWhereColumn("Status").matchValueRegex(/(New)/)
.getTableWhereColumn("Email").matchValue(mail);
// initialise html template
var htmltemplate=HtmlService.createTemplateFromFile("email")
htmltemplate.resource=resource
htmltemplate.status_r=status_r
htmltemplate.due_date_r=due_date_r
htmltemplate.link_r=link_r
var new_data = []
var htmlformail
// loop into the filtered table of target i only
for(var j=0; j< mailTable.length() ; j++){
// Any other value of column Target Value
var resource_col = mailTable.getWithinColumn("Resource").cellAtRow(j).getValue();
var status_col = mailTable.getWithinColumn("Status").cellAtRow(j).getValue();
var due_date_col = mailTable.getWithinColumn("Due Date").cellAtRow(j).getValue();
var link_col = mailTable.getWithinColumn("Link").cellAtRow(j).getValue();
new_data.push([resource_col,status_col,due_date_col,link_col])
}
htmltemplate.new_data=new_data
htmlformail=htmltemplate.evaluate().getContent()
var subjectMail = "Automation Support Services Actions Items";
var dt1 = new Date()
var dt2 = due_date_col
// get milliseconds
var t1 = dt1.getTime()
var t2 = dt2.getTime()
var diffInDays = Math.floor((t1-t2)/(24*3600*1000));
// 24*3600*1000 is milliseconds in a day
console.log(diffInDays);
// Send email
MailApp.sendEmail({
to:mail ,
subject: subjectMail,
htmlBody:htmlformail,
});
}
I'm not confident on the new_data.push([resource_col,status_col,due_date_col,link_col]), it's seems to be corect but I have no no way to verify that
Anyway thanks for using the utils script at https://github.com/SolannP/UtilsAppSsript, glad to see it help 👍

Adding color to Netsuite suitelet's sublist row depending upon the result

Is there any way to add colors to a sublist's row depending upon a condition. I have loaded a saved search to show output on a sublist. But now I want to highlight the rows if the difference between todays date and audit date(search output) is more than 100 days.
var search = nlapiLoadSearch('customrecord_cseg_properties', 'customsearch52');
var columns=search.getColumns();
var sublist = form.addSubList('customsublist', 'staticlist', 'List of properties');
for(var i = 0; i< columns.length; i++){
sublist.addField('customcolumn'+i, 'text', columns[i].getLabel());
}
var result= search.runSearch();
var resultIndex = 0,resultStep = 1000,resultSet,resultSets = [];
do {
resultSet = result.getResults(resultIndex, resultIndex + resultStep);
resultSets = resultSets.concat(resultSet);
resultIndex = resultIndex + resultStep;
} while (resultSet.length > 0);
nlapiLogExecution('DEBUG','The Total number of rows is',resultSets.length);
for(var w= 0; w<resultSets.length ;w++){
for(var x=0; x<columns.length; x++){
var temp;
temp=resultSets[w].getText(columns[x]);
if(temp==null || temp==''){
temp=resultSets[w].getValue(columns[x]);
}
sublist.setLineItemValue('customcolumn'+x, Number(w)+1,temp);
}
I couldn't find any functions in UI Builder API for Netsuite for doing this. Please let me know if there is any other way to do this. Above is the code which I have used to display search result in suitelet.
There is no native api for that.
You can do it by mainpulating the DOM on the client script onInit function.
Just keep in mind that DOM manipulation are risky since they can break if NetSuite will chnage the DOM structure.

How to add a line to a google spreadsheet via email?

I need a google apps script which can do the following:
if I send an email to my alias email, say to myemail+expenses#gmail.com, it adds a line in a specific google spreadsheet with data from that email. E.g. timestamp, subject, the first line of a body - whatever.
I found interesting article describing similar process of sending data to google spreadsheet.
May be there is no any direct way of doing that, however, it should exist some workaround.
P.S. It should be done only by using a google echosystem. No php, servers etc.
There are two step for this.
#1
At first create a trigger to run the mail checker.
function switchTrigger() {
var isExist = false;
var triggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < triggers.length; i++) {
if ( /*<CONDITION>*/ ) {
isExist = true;
ScriptApp.deleteTrigger(triggers[i]);
}
}
if (!isExist) {
ScriptApp.newTrigger( /*<CONDITION>*/ ).create();
Logger.log('create');
}
}
#2
Then you have to check emails. Something like that
function checkMail() {
var sh = SpreadsheetApp.openById(properties.targetSheetId).getSheets()[0];
var query = /* properties.queryString */ ;
var threads = GmailApp.search(query);
if (threads.length < 1) return;
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
for (var j = 0; j < messages.length; j++) {
if (messages[j].isStarred()) {
sh.appendRow([
new Date(),
messages[j].getFrom(),
messages[j].getPlainBody()
]);
messages[j].unstar();
}
}
}
}
Be careful. You have to set up Gmail filters so that all incoming to myemail+expenses#gmail.com would be marked with an star at the beginning.
Working Example

Export Email-adress from a label in Gmail using Apps Script

Hi im trying to export the Emailadresses from the senders in a label in Gmail Called "Suarez". But it's just running and never completing, it should be about 372 emails. Is it to much to print to the logger?
Here is what im trying:
function getEmailsadresses(){
var threads = GmailApp.search("in:suarez");
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
for (var m = 0; m < messages.length; m++) {
var msg = messages[m].getFrom();
}
}
Logger.log(msg()); // log from address of the message
}
I use a script embedded in an spreadsheet the reads every messages in every threads in a Label that could probably be a good starting point for you.
My specific use case was to log SMS messages that my android phone sends me as emails each time I send or receive a text message.
So it will work for you by just changing the label name and maybe remove the data filtering I added on the message. Since I have a lot of data I set up a time trigger task manager to works in small bunches to avoid exceeding time limit.
Usage is simple : run the "startSMSLog" and go have a couple of coffees until the cell A1 in the spreadsheet stops being RED... that's it.
Code below : the start function
function startSMSLog(){
var triggerID = ScriptApp.newTrigger('countSMSLogEmails').timeBased().everyMinutes(5).create().getUniqueId();
var thisTrigger = PropertiesService.getScriptProperties().setProperty('thisTriggerSMS',triggerID);
PropertiesService.getScriptProperties().setProperty('current thread SMS',0);
var sh = SpreadsheetApp.getActive().getSheetByName('SMS'); // change to the name of your sheet
sh.getRange('A1').setBackground('red');
countSMSLogEmails(true);
}
and the "working" code :
function countSMSLogEmails(clearSheet){
var sh = SpreadsheetApp.getActive().getSheetByName('SMS');
var start = Number(PropertiesService.getScriptProperties().getProperty('current thread SMS'));
var CallLogThreads = GmailApp.getUserLabelByName('SMS').getThreads(start,10);
if(CallLogThreads.length==0){
sh.sort(2,false);
sh.getRange('A1').setBackground('#FFC');
var triggers = ScriptApp.getProjectTriggers();
var thisTrigger = PropertiesService.getScriptProperties().getProperty('thisTriggerSMS');
for(var n in triggers){
if(triggers[n].getUniqueId()==thisTrigger){ScriptApp.deleteTrigger(triggers[n])};
}
sh.getRange('A1').setValue('Subject (Log on '+Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "dd-MMM-yy HH:mm")+')');
return;
} else {
PropertiesService.getScriptProperties().setProperty('current thread SMS',start+CallLogThreads.length);
}
var data = [];
for(var n=0;n<CallLogThreads.length;n++){
var thread = CallLogThreads[n];
Logger.log('thread message count = '+thread.getMessageCount());
var msg = thread.getMessages();
var msgData = [];
for(var m in msg){
var msgDate = msg[m].getDate();
var msgSubject = msg[m].getSubject();
var msgBody = msg[m].getBody().replace(/[\n\r]/g,' ').replace(/'/g,"'").replace(/ /g,"!").replace(/&/g,"&").replace(/"/g,'"')
.replace(/>/g,'>').replace(/</g,'<').replace(/<br \/>/g,'\n').replace(/<br>/g,'\n');
msgData.push([msgSubject,msgDate,msgBody]);
}
data.push(msgData);
}
var dataTotal = [];
if (clearSheet==true) {
dataTotal.push(['subject', 'date', 'message']);
}
for(var n in data){
dataTotal = dataTotal.concat(data[n]);
};
Logger.log(JSON.stringify(dataTotal));
if (clearSheet==true) {
sh.clearContents();
sh.getRange(1,1,dataTotal.length,dataTotal[0].length).setValues(dataTotal);
}else{
sh.getRange(sh.getLastRow()+1,1,dataTotal.length,dataTotal[0].length).setValues(dataTotal);
}
}

Google Spreadsheet Script problem - Error: Service Times Out: Apps Script

I've been trying to whip up a quick google script to count rsvps for the invite response spreadsheet for a wedding. The script worked perfectly for a week as new entries were added to the spreadsheet, then suddenly stopped working with the following error message in each cell:
Error: Service Times Out: Apps Script
The script itself is simple. It queries the relevant column (there are multiple events) and then checks to see whether there is some response spefied by the user - "YES", "NO", or a blank, typically.
What does this error mean, and does anyone have any suggestions for fixes?
function sumRSVP(response, rsvpType) {
var rsvpCol = 7;
if (rsvpType == "rehearsal") rsvpCol = 8;
if (rsvpType == "brunch") rsvpCol = 9;
var mySum = 0;
var sh = SpreadsheetApp.getActiveSheet();
for( i=2; i<177; i++){
var rsvp = sh.getRange(i, rsvpCol).getValue();
var nguests = sh.getRange(i, 6).getValue();
if(nguests != "" && rsvp == response){
mySum = mySum + parseFloat(nguests);
}
}
return mySum;
}
Hopefully the wedding went well. This was asked some time ago but has been viewed over 300 times at this post and I believe is important:
Data should not be extracted from a spreadsheet in a loop. The data needed should be extracted in a batch to an array and the array evaluated in the loop.
See docs reference at:
https://developers.google.com/apps-script/guide_common_tasks#OptimizeScripts
You can write scripts to take maximum advantage of the built-in caching, by minimizing the number of reads and writes. Alternating read and write commands is slow. To speed up a script, read all data into an array with one command, perform any operations on the data in the array, and write the data out with one command.
function sumRSVP(response, rsvpType) {
var rsvpCol = 7;
if (rsvpType == "rehearsal") rsvpCol = 8;
if (rsvpType == "brunch") rsvpCol = 9;
var mySum = 0;
var sh = SpreadsheetApp.getActiveSheet();
// start at row 2 - uses columns 6-9
var data = sh.getRange(2, 6, 177 - 1 , 4).getValues();
for(var i=0; i<data.length; i++){
var rsvp = data[i][rsvpCol - 6];
var nguests = data[i][0];
if(nguests != "" && rsvp == response){
mySum = mySum + parseFloat(nguests);
}
}
return mySum;
}