HELP! I’m using a script I basically cribbed from Tom Woodward at Bionice Teaching to record email messages in a spreadsheet.
http://bionicteaching.com/auto-logging-email-via-google-script/
I need to add a column that collects any labels that have been attached to the messages. I need to get this done for my work, but I'm brand new to Google Apps Script and really need someone to hold my hand... Essentially doing it for me, then teaching me what it was you did. I really appreciate any help you can give me in any case. Thanks
Here is what I’m using:
function myFunction() {
//this is just the stuff that recognizes what spreadsheet you're in
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var sheet = ss.getSheetByName("data"); //gets the right sheet
//this chunk gets the date info
var today = new Date();
var dd = today.getDate()-1;
var mm = today.getMonth()+1; //January is 0 DO NOT FORGET THIS
var yyyy = today.getFullYear();
var yesterday = yyyy + '/' + mm + '/' + dd;
//****************************************************
//searches your GMail for emails written after yesterday
var query = "after:" + yesterday;
var threads = GmailApp.search(query);
Logger.log('threads len ' + threads.length);
Logger.log(query);
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
Logger.log(messages);
for (var m = 0; m < messages.length; m++) {
var supportStats = [];
//here's where you decide what parts of the email you want
var from = messages[m].getFrom(); //from field
Logger.log(from);
var time = messages[m].getDate();//date field
Logger.log(time);
var subject = messages[m].getSubject();//subject field
Logger.log(subject);
var body = messages[m].getPlainBody();//body field
Logger.log(body);
var mId = messages[m].getId();//id field to create the link later
var mYear = time.getFullYear();
var mMonth = time.getMonth()+1;
var mDay = time.getDate();
var messageDate = mYear + '/' + mMonth + '/' + mDay;
Logger.log('msg date ' + messageDate);
//decides what found emails match yesterday's date and push them to an array to write to the spreadsheet
if (messageDate === yesterday) {
supportStats.push(from);
supportStats.push(time);
supportStats.push(subject);
supportStats.push(body);
supportStats.push('https://mail.google.com/mail/u/0/#inbox/'+mId); //build the URL to the email
SpreadsheetApp.getActiveSheet().appendRow(supportStats); //writes to the spreadsheet
}
}
}
}
Here is the results I'm getting... Perfect!
Except I'd like one more column that adds the labels that are on each message. How do I do that?
spreatsheet results of Google Apps script mail->sheet
You can use this:
var labels = threads[i].getLabels();
GmailThread::getLabels()
GmailThread has labels, not GmailMessage. It returns an array of labels. Maybe use:
var labelsString = "";
var labelArray = []
for each (var label in labels)
{
labelArray.push(label.getName());
}
if (labelArray.length > 0)
{
labelsString = labelArray.join(',');
}
to insert into the row of the spreadsheet.
GmailLabel::getName()
Related
Am new dabbling with Google Apps Script; would like to ask if I'm in the right direction, and how to I manipulate time within the script.
I'm struggling in trying to maniuplate time values in Google App Script, basically I am able to pull the timestamp of each email sent, but I only want to paste into the spreadsheet email information that were recent, e.g. within 30minutes from script run time. This is to avoid pulling duplicate information.
Not sure if there is a currentTime() function here, or I have to create a new Date() object and do some calculations from there. Tried a few variations and nothing seemed to work proper.
Would appreciate any help in getting towards the right direction in doing this thank you!
function getDetails(){
var DEST_URL = "SHEET_URL"; //redacted for sensitivity
var DEST_SHEETNAME = "Test";
var destss = SpreadsheetApp.openByUrl(DEST_URL);
var destSheet = destss.getSheetByName(DEST_SHEETNAME);
var threads = GmailApp.search("FILTERS"); //filter settings redacted for sensitivity
for(var i = 0; i < threads.length; i++){
var messages=threads[i].getMessages();
for(var j =0; j < 1; j++){ //only take first message in thread
var message = messages[j];
var subject = message.getSubject() ;
var sentTimeStamp = message.getDate();
if(sentTimeStamp is within last 30minutes as of script run time){ //this is where i need help
var delimitString = subject.split("is sent");
var detailName = delimitString[0];
var lastRow = destSheet.getLastRow();
destSheet.getRange(lastRow + 1,1).setValue(detailName);
destSheet.getRange(lastRow + 1,2),setValue(sentTimeStamp);
}
}
}
}
You can convert timeStamp into ms seconds and then compare to the value of "30 s ago"
Sample:
var sentTimeStamp = message.getDate();
var now = new Date();
var ThirtyMinutesAgo = now-30*60*1000;
if(sentTimeStamp.getTime() < ThirtyMinutesAgo){
...
}
References:
newDate()
getTime()
Another idea would be to query for emails that you received the last 30 minutes.
Explanation:
You can get the emails that you received the last 30 minutes ago as a query in the GmailApp.search function. See this link to see what filters you can use.
This will get the last emails with keyword "FILTERS" that you received the last 30 minutes.
var ThirtyMinutesAgo = new Date();
ThirtyMinutesAgo.setMinutes(ThirtyMinutesAgo.getMinutes() - 30);
const queryString = `"FILTERS" newer:${Math.round(ThirtyMinutesAgo.getTime()/1000)}`
const threads = GmailApp.search(queryString); // threads the last 30 minutes
This approach is more efficient for two reasons:
You have less data (threads) to iterate over with the for loop.
You don't need to apply and if statement on every thread.
Solution:
function getDetails(){
var DEST_URL = "SHEET_URL"; //redacted for sensitivity
var DEST_SHEETNAME = "Test";
var destss = SpreadsheetApp.openByUrl(DEST_URL);
var destSheet = destss.getSheetByName(DEST_SHEETNAME);
// var threads = GmailApp.search("FILTERS"); //filter settings redacted for sensitivity
// new code
var ThirtyMinutesAgo = new Date();
ThirtyMinutesAgo.setMinutes(ThirtyMinutesAgo.getMinutes() - 30);
const queryString = `"FILTERS" newer:${Math.round(ThirtyMinutesAgo.getTime()/1000)}`
const threads = GmailApp.search(queryString); // threads the last 30 minutes
//
for(var i = 0; i < threads.length; i++){
var messages=threads[i].getMessages();
for(var j =0; j < 1; j++){ //only take first message in thread
var message = messages[j];
var subject = message.getSubject() ;
var sentTimeStamp = message.getDate();
var delimitString = subject.split("is sent");
var detailName = delimitString[0];
var lastRow = destSheet.getLastRow();
destSheet.getRange(lastRow + 1,1).setValue(detailName);
destSheet.getRange(lastRow + 1,2),setValue(sentTimeStamp);
}
}
}
}
I'm trying to add a counter using App Scripts –> Google Sheets so that every time I receive a webhook, the value is increased by 1 in a certain cell.
Everything works when I test it using a dummy function in the Google Appscript Editor, but it's not working when I send the actual webhook using the doPost(e) method.
I've spent about 2 weeks learning how to read/write Javascript, troubleshooting with YouTube videos, and reading the Google Sheets API, and I'm sooo close to cracking the code... but I'm stuck on this last part. It's probably something simple I'm missing.
Could you help please? Will pay $3 million dollars
//ACCEPT WEBHOOK FROM ACTIVECAMPAIGN
function doPost(e) {
return updateMetrics(e)
}
function updateMetrics(e){
var selectedMetric = e.parameter.metric;
//GET TODAY'S DATE
var today = new Date();
var dd = String(today.getDate());
var mm = String(today.getMonth() + 1); //January is 0!
var yyyy = today.getFullYear();
today = mm + '/' + dd + '/' + yyyy;
var monthMetrics = mm + '/' + yyyy;
var spreadsheetId = '1UfRFM7Uz0YUqemPTVYe1lmZ5NC5v9naFvmlLvXPZuVM';
var rangeName = monthMetrics + '!A2:I35';
var stringSheet = JSON.stringify(monthMetrics);
var stringToday = JSON.stringify(today)
var metricsSheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(monthMetrics)
// GET METRICS COLUMN NUMBER
function getColumnNrByName(sheet, metric) {
var range = sheet.getRange(1, 1, 1, sheet.getMaxColumns());
var values = range.getValues();
for (var row in values) {
for (var col in values[row]) {
if (values[row][col] == metric) {
return parseInt(col);
}
}
}
throw 'failed to get column by name';
}
var metricColumn = getColumnNrByName(metricsSheet, selectedMetric)
// GET PREVIOUS METRICS AMOUNT
function getPreviousAmount(sheet, column, metric, date, metriccolumn){
var lastRow=sheet.getLastRow();
var data=sheet.getRange(1,column,lastRow,column+metric).getValues();
for(i=0; i <data.length; ++i){
if (data[i][0]==date){
return data[i][metric];
}
}
}
var previousAmount = getPreviousAmount(metricsSheet, 1, metricColumn, today, metricColumn)
// SET NEW METRIC
function setNewMetric(sheet, column, metric, date, amount){
var lastRow=sheet.getLastRow();
var data=sheet.getRange(1,column,lastRow,column+metric).getValues();
for(i=0;i<data.length;++i){
if (data[i][0]==date){
return sheet.getRange(i+1, column+metric).setValue(amount+1);
}
}
}
var metricScript = setNewMetric(metricsSheet, 1, metricColumn, today, previousAmount);
}
if i use SpreadsheetApp.getActiveSpreadsheet() it works but i can't run this script with a minute-based trigger because it doesn't have an active spreadsheet.
i tried to use SpreadsheetApp.openByUrl() which runs manually inside the script editor and also runs without error from the minute-based trigger.
my problem is that no cells are updated on my actual sheet which it is supposed to output onto. i think that it's not marking the emails as read either but i receive so many constantly already that it's hard to check at the moment.
https://jsfiddle.net/29Ls3me4/1/
function myFunction() {
//var ss = SpreadsheetApp.getActiveSpreadsheet();
var ss = SpreadsheetApp.openByUrl("https://docs.google*****************************/edit");
var sheet = ss.getSheetByName("sheet1");
var threads = GmailApp.search ('label:unread "Thank you for your order!" -fwd: -re: -failure'); //search string
for (var i=0; i<threads.length; i++)
{
var messages = threads[i].getMessages();
for (var j=0; j<messages.length; j++)
{
var msg = messages[j].getPlainBody();
var sub = messages[j].getSubject();
var dat = messages[j].getDate();
var to = messages[j].getTo();
var dateString =
dat.getUTCFullYear() + "/" +
("0" + (dat.getUTCMonth()+1)).slice(-2) + "/" +
("0" + dat.getUTCDate()).slice(-2);
var name = messages[j].getSubject();
var invoicenumber = name.match(/\d/g);
if(invoicenumber == null){
invoicenumber = "null";
} else {
invoicenumber = invoicenumber.join("");
}
ss.appendRow([invoicenumber, dateString, to, sub, msg])
}
threads[i].markRead();
//threads[i].markUnread();
}
}
ok simple coding eyeballs
ss.appendRow()
should've been
sheet.appendRow()
Trying to send an email to a list in a Google Sheet, but only if column N gets marked "Yes." Acceptable data in column N is "Yes" or "No" so I want to test that and send emails only to the rowData that contain "yes" there. Then write the date in the adjacent column on the same row. I can't seem to figure out how to iterate through the array of objects and couldn't find any good resources to explain this. Help greatly appreciated. My best effort was emailing all the rows and then also filling in the date no matter what was in column N (Yes/No/Blank).
function sendEmails() {
validateMySpreadsheet() //a function that checks for "Yes" in column N
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getActiveSheet();
var dataRange = dataSheet.getRange(2, 1, dataSheet.getMaxRows() - 1, 16);
var d = new Date();
var dd = d.getDate();
var mm = d.getMonth() + 1; //Months are zero based
var yyyy = d.getFullYear();
var date = mm + "/" + dd + "/" + yyyy;
var needsaYes = "Yes";
//Gets the email template
var templateSheet = ss.getSheetByName("Template");
var emailTemplate = templateSheet.getRange("A1").getValue();
// Create one JavaScript object per row of data.
objects = getRowsData(dataSheet, dataRange);
//This is where I am stuck - how to check if column N contains a "Yes" before allowing the MailApp.SendEmail command to run.
for (var i = 0; i < objects.length; ++i) {
// Get a row object
var rowData = objects[i];
var values = dataRange.getValues();
for (var j = 0; j < values.length; ++j) {
var row = values[j];
var checkFirst = row[13]; //row J, Column N?
if (checkFirst = needsaYes) { //does column N contain "Yes"?
var emailText = fillInTemplateFromObject(emailTemplate, rowData);
var emailSubject = "mySubject";
MailApp.sendEmail(rowData.email, emailSubject, emailText);
dataSheet.getRange(2 + i, 15).setValue(date); //then write the date
SpreadsheetApp.flush();
}
}
}
}
I didn't check whole code but
if (checkFirst = needsaYes)
It may be the problem, you need to use ==
I figured it out I needed to just use the .getValues() method for my data range rather than the whole sheet and also remove the unnecessary second for loop:
var rowData = objects[i]; var checkData = ss.getActiveSheet().getDataRange().getValues();
var row = checkData[i]
var colN = row[13] if (colN == needsaYes) { //etc.
I'm currently working on creating a Google Sheet that would allow me to create calendar events (reminders) for when certain reports are due for me.
Basically, on the basis of a given opening date, I have 5 different types of reports due, some at different intervals (ie, 45 days from the open date, 6 months, 12 months). I've been able to modify a sample I found online (http://www.adammcfarland.com/2013/08/09/tutorial-using-google-spreadsheets-to-update-a-google-calendar-our-new-vacation-management-system/), customizing a Google Sheet to generate due dates for each type of report, and create calendar entries based on those due dates. It's actually really cool and powerful.
Unfortunately, I'm stumbling when it comes to creating notifications for the different reports. I know how to create default notifications within the Google Calendar interface, but the quirk I'm currently trying to address is that of these various reports, not all require as much time to complete, so I'm looking to create notifications specific to each report type, and I'm thus far been wholly unable to get things working.
Here's a copy of the script I'm using.
enter code herefunction pushToCalendar() {
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
var range = sheet.getRange(2,1,lastRow,5);
var values = range.getValues();
var updateRange = sheet.getRange('G1');
var calendar = CalendarApp.getCalendarById('jk.com_5e9gk4#group.calendar.google.com')
updateRange.setFontColor('red');
var numValues = 0;
for (var i = 0; i < values.length; i++) {
if ((values[i][0].length > 0) && (values[i][2].length > 0)) {
if (values[i][3] != 'y') {
var newEventTitle = 'Note Due: ' + values[i][0] + ' - ' + values[i][2];
var newEvent = calendar.createAllDayEvent(newEventTitle, values[i][1]);
var newEventId = newEvent.getId();
sheet.getRange(i+2,4).setValue('y');
sheet.getRange(i+2,5).setValue(newEventId);
}
Where "values[i][2]" corresponds to the type of report due.
Thanks in advance.
You can try to addreminder just after creating event based on a table. See the code below :
function pushToCalendar() {
var sheet = SpreadsheetApp.getActiveSheet();
//Define reminder, value in minute and lower 4weeks (=40320 minutes)
var reminder = {"type1":1440,//=1 day
"type2":7200,//5days
"type3":20160//2weeks
};
//End define reminder
var lastRow = sheet.getLastRow();
var range = sheet.getRange(2,1,lastRow,5);
var values = range.getValues();
var updateRange = sheet.getRange('G1');
var calendar = CalendarApp.getCalendarById('jk.com_5e9gk4#group.calendar.google.com')
updateRange.setFontColor('red');
var numValues = 0;
for (var i = 0; i < values.length; i++) {
if ((values[i][0].length > 0) && (values[i][2].length > 0)) {
if (values[i][3] != 'y') {
var newEventTitle = 'Note Due: ' + values[i][0] + ' - ' + values[i][2];
var newEvent = calendar.createAllDayEvent(newEventTitle, values[i][1]);
//Add reminder
//For that we assume you well created the reminder var and all type have the amount of minutes define if not you must implement the check in he code
newEvent.addEmailReminder(reminder[values[i][2]]);
//End add reminder
var newEventId = newEvent.getId();
sheet.getRange(i+2,4).setValue('y');
sheet.getRange(i+2,5).setValue(newEventId);
}
}
}
}
I added some comments in the code for you.
Stéphane