Get message sender address from Gmail API - google-apps-script

Let me preface my question by saying that I am not a JS dev, or even a web dev, so bear with me! I'm trying to create a gs script that deletes messages that are older than n months that have a certain label and are from a given sender.
I think I have it down, but the Gmail API getFrom() method seems to return the sender's address in the format "First Last" <address#mail.tld> rather than just address#mail.tld. Currently I can work around this by the fact that I know this information, but is there a better way of doing this so that the code operates solely on the actual email address?
My current code:
function auto_delete_emails() {
var label = GmailApp.getUserLabelByName("foo");
var sender = "\"Foo Bar\" <info#foo.bar>";
if (label != null) {
var delayDays = 30
var maxDate = new Date();
maxDate.setDate(maxDate.getDate() - delayDays);
var threads = label.getThreads();
for (var i = 0; i < threads.length; i++) {
var messages = GmailApp.getMessagesForThread(threads[i]);
var from = messages[0].getFrom();
if (from == sender) {
if (threads[i].getLastMessageDate < maxDate) {
threads[i].moveToTrash();
}
}
}
}
}
I have seen a question that used a regex to fix this, but I barely understand regex, never mind how to apply in this context or how the example worked (or didn't!).
Suggestions for other improvements on this code also welcome.

I think extracting the email address from the From-header is your safest bet. You can use e.g. this great RegEx:
function extractEmailAddress(header) {
return header.match(/[^#<\s]+#[^#\s>]+/)[0];
}
function auto_delete_emails() {
var label = GmailApp.getUserLabelByName("foo");
var sender = extractEmailAddress("\"Foo Bar\" <info#foo.bar>");
if (label != null) {
var delayDays = 30;
var maxDate = new Date();
maxDate.setDate(maxDate.getDate() - delayDays);
var threads = label.getThreads();
for (var i = 0; i < threads.length; i++) {
var messages = GmailApp.getMessagesForThread(threads[i]);
var from = extractEmailAddress(messages[0].getFrom());
if (from === sender) {
if (threads[i].getLastMessageDate < maxDate) {
threads[i].moveToTrash();
}
}
}
}
}

Related

Running script for multiple search terms found on different sheet

I'm trying to get a SCORESHEET to populate from a REPORTSHEET, using a REFERENCESHEET to collate search terms and destination cells.
The script I'm running is as below. The idea is that the script finds searchDate's in the REFERENCESHEET and uses them to locate data columns in the REPORTSHEET:
function superAuto() {
var report = SpreadsheetApp.openById('REPORTSHEET');
var reportData = report.getDataRange().getValues();
var reference = SpreadsheetApp.openById('REFERENCESHEET');
var referenceData = reference.getDataRange().getValues();
var scorecard = SpreadsheetApp.openById('SCORESHEET');
var scorecardData = scorecard.getDataRange().getValues();
var tExpenses = "Total Expenses";
for(n=0;n<referenceData.length;++n){
var searchDate = referenceData[n][0] ;
Logger.log (searchDate)
}
var column = columnfinder(searchDate);
for (var a = 0; a < referenceData.length; a++) {
var refRow = referenceData[a];
for (var i = 0; i < reportData.length; i++) {
var row = reportData[i];
if (row[0] == tExpenses && refRow[0] == searchDate) {
scorecard.getRange(refRow[5]).setValue(row[column]);
}
}
}
}
function columnfinder(find) {
var report = SpreadsheetApp.openById('REPORTSHEET');
var reportData = report.getDataRange().getValues();
var reference = SpreadsheetApp.openById('REFERENCESHEET');
var referenceData = reference.getDataRange().getValues();
for(var j=0, jLen=reportData.length; j<jLen; j++) {
for(var k=0, kLen=reportData[0].length; k<kLen; k++) {
if(find == reportData[j][k]) {
Logger.log(k);
return (k);}
}
}
}
Broadly speaking, the code works, as if I define searchDate as one of the terms I'm looking for (e.g. Jan-21) it all works fine. The issue is that it doesn't seem to be doing so when finding multiple search terms - and therefore populating multiple rows - as per:
for(n=0;n<referenceData.length;++n){
var searchDate = referenceData[n][0] ;
Logger.log (searchDate)
}
The log tells me that it's finding searchDate's in the REFERENCESHEET, but it's not able to run them through function columnfinder (I get no logs for the second logger).
I suspect the answer lay somewhere in an earlier great answer I received to an earlier version of this idea - How to return multiple column values for setValue - but I've not been able to make it fit. Any thoughts?
EDIT: Please find a sample REFERENCESHEET & REPORTSHEET for more info:
The log tells me that it's finding searchDate's in the REFERENCESHEET,
but it's not able to run them through function columnfinder (I get no
logs for the second logger)
You don't execute columnfinder inside the for loop.
Try this:
for(n=0;n<referenceData.length;++n){
var searchDate = referenceData[n][0] ;
Logger.log(searchDate);
columnfinder(searchDate); // modified code
}
and you will get both logs.
Sorry if I misunderstood your question.
You need to use have it assigned to array since you are returning possible multiple columns/dates:
function superAuto() {
var report = SpreadsheetApp.openById('REPORTSHEET');
var reportData = report.getDataRange().getValues();
var reference = SpreadsheetApp.openById('REFERENCESHEET');
var referenceData = reference.getDataRange().getValues();
var scorecard = SpreadsheetApp.openById('SCORESHEET');
var scorecardData = scorecard.getDataRange().getValues();
var tExpenses = "Total Expenses";
var searchDates = [];
for (n = 0; n < referenceData.length; ++n) {
searchDates.push(referenceData[n][0])
}
var columns = columnfinder(searchDates);
columns.forEach(function (column, index) {
referenceData.forEach(function (refRow) {
reportData.forEach(function (row) {
if (row[0] == tExpenses && refRow[0] == searchDates[index]) {
scorecard.getRange(refRow[5].toString()).setValue(row[column]);
}
});
});
});
}
function columnfinder(dates) {
var report = SpreadsheetApp.openById('REPORTSHEET');
var reportData = report.getDataRange().getValues();
var reference = SpreadsheetApp.openById('REFERENCESHEET');
var referenceData = reference.getDataRange().getValues();
var columns = [];
dates.forEach(function (date) {
reportData.forEach(function (row, i) {
row.forEach(function (col, i) {
if (date == reportData[i][j]) {
columns.push(reportData[i][j]);
}
});
});
});
return columns;
}
I changed some variables into proper variable names to avoid confusion.
Additionally, if it doesn't work, you might need to share a proper visualization of the data, or better yet, provide some sample sheet we can work on for us to be able to give you a better and tested answer.
Thanks Marios, that's twice in a week. Much appreciated.
Slight adaptation, in order for it to populate SCORECARD I needed to bring everything into the for loop, as below:
for(n=0;n<referenceData.length;++n){
var searchDate = referenceData[n][0] ;
Logger.log (searchDate)
var column = columnfinder(searchDate);
for (var a = 0; a < referenceData.length; a++) {
var refRow = referenceData[a];
for (var i = 0; i < reportData.length; i++) {
var row = reportData[i];
if (row[0] == tExpenses && refRow[0] == searchDate) {
scorecard.getRange(refRow[5]).setValue(row[column]);
}
}
}
}

Count all eMails from a Label

i have create this script:
function myTest() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var label = GmailApp.getUserLabelByName("Label1");
var threads = label.getThreads();
var countMail = 0;
//get first message in first thread
for (var i = 0; i < threads.length; i++) {
var messages=threads[i].getMessages();
countMail = countMail + messages.length;
}
ss.getRange(1,1).setValue(countMail);
}
it runs nearly perfect. Here I get all eMails back which are connected with this treads (marked with Label1 or not).
Does anyone can share a simply script how I can count all eMails which are "realy" marked with the Label.
Thanks
Try this:
function labelMsgs(){
var labels = Gmail.Users.Labels.list("me").labels;
var lblId;
for (var i = 0; i < labels.length; i ++){
if (labels[i].name == "Label1"){
lblId = labels[i].id;
break;
}
}
var optionalArgs = {
"labelIds" : lblId,
"maxResults" : 200
}
var messages = Gmail.Users.Messages.list("me", optionalArgs).messages;
}
This method uses the Gmail API directly, for this you'll need to enable Google Advanced Services, it will return a list of all messages tagged with the "Label1" label. You can play around with maxResults and with the pageToken to see more results, but this is the general approach.

Need to split the row based on Error and Warning and remove particular content

While run the provided script its working perfect, but need to modify. this is the screenshot tells what i need, i am trying to change script , please help me if you can
function autocopy() {
var label = GmailApp.getUserLabelByName("Sanmina EDI Failed Concurrent Jobs Alert");
var threads = label.getThreads();
var read = threads.getMessages();
var uread = threads.isUnread();
for(var i = 0; i <= uread.length; i++) {
var message=uread(i);
}
var message1 = new message.Date();
var day = message1.getUTCDate();
var bodycontent = message.getbody();
var action = bodyContents.search("Invoice")
var action1 = bodyContents.search("Error")
var action2 = bodyContents.search("Terminated")
if (action > 0) {
var out ="Need to create SR"
} else if (action1 > 0 || action2 > 2) {
var out ="Need to create SR"
} else {
var out ="Printing output file"
}
var activeSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
activeSheet.appendRow([day, bodycontent, out]);
}
I want to extract the data from email to spreadsheet,by reading unread thread id and using for looping the reach from read thread id to unread thread id and print the mail body content and date from the unread email.
I reworked your code a bit. Put some comments in it so that you can see clearly what is happening in each line. Your issue was that you were trying to use methods on the wrong objects (for example, an array of threads does not have a getMessages method, so you have to loop through each thread and get the messages for each specific thread).
function autocopy() {
var label = GmailApp.getUserLabelByName("Sanmina EDI Failed Concurrent Jobs Alert");
// Get all threads belonging to this label
var threads = label.getThreads();
// Loop through each thread
for (var i = 0; i < threads.length; i++) {
// Check whether thread is unread
if (threads[i].isUnread()) {
// Get all messages for each unread thread
var messages = threads[i].getMessages();
// Loop through all messages for each unread thread
for (var j = 0; j < messages.length; j++) {
// Check whether message is unread
// (delete this condition if you want all messages in an unread
// thread to be printed in your spreadsheet, read or unread)
if (messages[j].isUnread()) {
var day = messages[j].getDate();
var bodyContent = messages[j].getBody(); // Use getPlainBody() instead if you don't want html tags;
var action = bodyContent.search("Invoice");
var action1 = bodyContent.search("Error");
var action2 = bodyContent.search("Terminated");
if (action > 0) {
var out = "Need to create SR"
} else if (action1 > 0 || action2 > 2) {
var out = "Need to create SR"
} else {
var out = "Printing output file"
}
var activeSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
activeSheet.appendRow([day, bodyContent, out])
}
}
}
}
}
I hope this works for you!

Google Apps Script performing Index & Match function between two separate Google Sheets

I am using Google Apps Script to perform a Index and Match function between two separate Google Sheets and retrieve the matching records and populate the designated sheet and column. Although it works fairly well, I would like to get the script to run more efficiently and as such use less time. Could Someone please look at the code example below and provide me with advice/pointers to do so
function SiteIDLookup() {
var search_spreadsheet = SpreadsheetApp.openById("GoogleSheetId");
SpreadsheetApp.setActiveSpreadsheet(search_spreadsheet);
var find_spreadsheet = SpreadsheetApp.openById("GoogleSheetId");
SpreadsheetApp.setActiveSpreadsheet(find_spreadsheet);
var ssheet = search_spreadsheet.getSheetByName("schoolSiteID_Lookup");
var fsheet = find_spreadsheet.getSheetByName("Info_Formatted");
var FMaxR = fsheet.getMaxRows();
fsheet.getRange(2, 16, FMaxR, 1).clear({contentsOnly: true});
var findData = fsheet.getDataRange().getValues();
var searchData = ssheet.getDataRange().getValues();
for(var i=0; i < findData.length; i++) {
for(var j=0; j < searchData.length; j++) {
var find = findData[i][14];
var searchref = searchData[j][0];
if(find == searchref && find != "" ) {
var found = ssheet.getRange(j+1,2,1,1).getDisplayValue();
fsheet.getRange(i+1,16,1,1).setValue(found);
}
}
}
}
The comment on your question is pretty much correct. You are doing unnecessary actions like
SpreadsheetApp.setActiveSpreadsheet(search_spreadsheet);
SpreadsheetApp.setActiveSpreadsheet(find_spreadsheet);
which serve no purpose. Then inside of the loops you perform an unnecessary action
var found = ssheet.getRange(j+1,2,1,1).getDisplayValue();
considering you already did var searchData = ssheet.getDataRange().getValues(); that command line is redundant and is performed at each iteration to boot. You have 2 data sets in arrays, you need to work with arrays and use .setValues(array) to output the data. Something along the lines of this (you would have to check the indexing etc, since I don't have the actual sheets to test this on)
function SiteIDLookup() {
// --------------------------------------------------------------------
// This bit is purely cosmetic, I personaly hate declaring variables
// inside of loops or middle of the code
var i, j
var find
var searchref
var found = []
// --------------------------------------------------------------------
var search_spreadsheet = SpreadsheetApp.openById("GoogleSheetId");
var find_spreadsheet = SpreadsheetApp.openById("GoogleSheetId");
var ssheet = search_spreadsheet.getSheetByName("schoolSiteID_Lookup");
var fsheet = find_spreadsheet.getSheetByName("Info_Formatted");
var FMaxR = fsheet.getMaxRows();
fsheet.getRange(2, 16, FMaxR, 1).clear({contentsOnly: true});
var findData = fsheet.getDataRange().getValues();
var searchData = ssheet.getDataRange().getValues();
for (i = 0; i < findData.length; i++) {
for (j = 0; j < searchData.length; j++) {
find = findData[i][14];
searchref = searchData[j][0];
if (find == searchref && find != "" ) {
found[i] = searchData[j][1]
}
else {
found[i] = ['']
}
// found = ssheet.getRange(j+1,2,1,1).getDisplayValue();
// fsheet.getRange(i+1,16,1,1).setValue(found);
}
}
fsheet.getRange(2, 16, found.length, 1).setValues(found)
}

Star a Gmail message with google script

I'm totally new to Google Script and I'm trying to find out how to star a message that I have labeled as "R/R(short)/R(ASAP)" and has held that label for at least a day. Any suggestions? Here's what I've got so far:
function star2do() {
var delayDays = 1 // Enter # of days before messages are starred
var maxDate = new Date();
maxDate.setDate(maxDate.getDate()-delayDays);
var label = GmailApp.getUserLabelByName("R/R(short)/R(ASAP)");
var threads = label.getThreads();
for (var i = 0; i < threads.length; i++) {
if (threads[i].getLastMessageDate()<maxDate)
{
threads[i].markUnread();
threads[i].addLabel(star) //this is where I'm having issues
}
}
}
threads[i].getMessages()[0].markUnread().star();
Hope this helps :)