Add label to all emails in inbox to who I replied? - google-apps-script

How would I go about Google Apps scripting to apply a label to all emails in my inbox to which I had replied?
I was looking at Gmail's filters but couldn't figure out how to construct this filter.

How about this sample script? Although I looked for the sample script for this situation, unfortunately I couldn't also find. So I created this as my try, because I also wanted to use this script. The concept of this script is as follows.
When there are more than 2 messages in a thread, there might be a possibility to have replied.
For more than 2 messages in a thread
The email address of "from" for the 1st message is the sender's address.
When the email address of "to" of after 2nd messages is the same to that of "from" of 1st one, it is indicates that the thread was replied by owner.
I prepared a sample script from above concept.
Sample script :
In order to use this sample, please input label. When run myFunction(), the label is added to the mails that owner replied in Inbox.
function myFunction() {
var label = "temp"; // Please input a label you want to use.
var threadId = "";
var thread = GmailApp.getInboxThreads();
thread.forEach(function(th) {
th.getMessages().forEach(function(msg) {
var mm = msg.getThread().getMessages();
if (mm.length > 0) {
var temp = [];
mm.forEach(function(m) {
var re = /<(\w.+)>/g;
var from = m.getFrom();
var to = m.getTo();
temp.push({
from: from.match(re) ? re.exec(from)[1] : from,
to: to.match(re) ? re.exec(to)[1] : to
});
});
if (temp.length > 1 && threadId != th.getId()) {
if (temp.filter(function(e){return temp[0].from == e.to}).length > 0) {
var rr = th.addLabel(GmailApp.getUserLabelByName(label));
Logger.log("Label '%s' was added to threadId %s.", label, rr.getId())
}
threadId = th.getId();
}
}
});
});
}
Note :
The mails that it was replied to the mails that owner sent are not retrieved.
If you use this sample script, please test using for example var th = GmailApp.getInboxThreads(0, 50);, and understand the flow. And please run above script.
Reference :
GmailApp
addLabel()
If I misunderstand your question, I'm sorry.
Edit 1 :
In order to use this sample script, please enable Gmail API at Advanced Google Services and API console. The flow of it is as follows.
Enable Gmail API v1 at Advanced Google Services
On script editor
Resources -> Advanced Google Services
Turn on Gmail API v1
Enable Gmail API at API console
On script editor
Resources -> Cloud Platform project
View API console
At Getting started, click Enable APIs and get credentials like keys.
At left side, click Library.
At Search for APIs & services, input "Gmail". And click Gmail API.
Click Enable button.
If API has already been enabled, please don't turn off.
If now you are opening the script editor with the script for using Gmail API, you can enable Gmail API for the project by accessing this URL https://console.cloud.google.com/apis/api/gmail.googleapis.com/overview
Sample script :
This script adds a label to only replied email. addLabel of GmailApp adds a label to only the thread. This cannot add the label to the specific messages in the thread. So I used Gmail API. When you use this script, please modify label, userId and thread for your environment.
function myFunction() {
var label = "#####"; // Please input a label you want to use.
var userId = "me"; // If you use this script by yourself, userId is "me".
var thread = GmailApp.getInboxThreads(); // In this setting, all mails in Inbox are retrieved. If you want to use the specific mails, please modify here.
var threadId = "";
thread.forEach(function(th) {
th.getMessages().forEach(function(msg) {
var mm = msg.getThread().getMessages();
if (mm.length > 0) {
var temp = [];
mm.forEach(function(m) {
var re = /<(\w.+)>/g;
var from = m.getFrom();
var to = m.getTo();
temp.push({
from: from.match(re) ? re.exec(from)[1] : from,
to: to.match(re) ? re.exec(to)[1] : to,
threadId: th.getId(),
messageId: m.getId()
});
});
if (temp.length > 1 && threadId != th.getId()) {
if (temp.filter(function(e){return temp[0].from == e.to}).length > 0) {
var receivedFrom = temp.filter(function(e){return e.threadId == e.messageId})[0].from;
temp.filter(function(e){return e.to == receivedFrom}).forEach(function(e){
Gmail.Users.Messages.modify(
{"addLabelIds": [Gmail.Users.Labels.list(userId).labels.filter(function(e){return e.name == label})[0].id]},
userId,
e.messageId
);
Logger.log("Label '%s' was added to messageId '%s'.", label, e.messageId)
});
}
threadId = th.getId();
}
}
});
});
}
Note :
In this sample script, var thread = GmailApp.getInboxThreads(); to retrieve threads is used. This means that all threads in Inbox are retrieved. So please modify this if you want to retrieve the specific threads.
Edit 2 :
The flow of this modified script is as follows.
Received an email from user A.
You reply to the received email.
The label is added to this message.
Received a reply from user A
If you replied to the 1st message, the label is added to this message.
Script :
function myFunction() {
var label = "#####"; // Please input a label you want to use.
var userId = "me"; // If you use this script by yourself, userId is "me".
var thread = GmailApp.getInboxThreads(); // In this setting, all mails in Inbox are retrieved. If you want to use the specific mails, please modify here.
var threadId = "";
thread.forEach(function(th) {
th.getMessages().forEach(function(msg) {
var mm = msg.getThread().getMessages();
if (mm.length > 0) {
var temp = [];
mm.forEach(function(m) {
var re = /<(\w.+)>/g;
var from = m.getFrom();
var to = m.getTo();
temp.push({
from: from.match(re) ? re.exec(from)[1] : from,
to: to.match(re) ? re.exec(to)[1] : to,
threadId: th.getId(),
messageId: m.getId()
});
});
if (temp.length > 1 && threadId != th.getId()) {
if (temp.filter(function(e){return temp[0].from == e.to}).length > 0) {
var receivedFrom = temp.filter(function(e){return e.threadId == e.messageId})[0].from;
if (temp.filter(function(e){return e.to == receivedFrom}).length > 0) {
temp.forEach(function(e, i){
if (i > 0) {
Gmail.Users.Messages.modify(
{"addLabelIds": [Gmail.Users.Labels.list(userId).labels.filter(function(e){return e.name == label})[0].id]},
userId,
e.messageId
);
Logger.log("Label '%s' was added to messageId '%s'.", label, e.messageId)
}
});
}
}
threadId = th.getId();
}
}
});
});
}
Edit 3:
A sends email to me.
I respond and keep this email in my inbox.
A responds to my response.
A’s response comes as a second email because conversations view is off.
I am not going to respond again to his email from 4.
I am running the script. 1. Should be labelled but 4. Should not be labelled
I could know that you want to add the label to only 2 for above situation. In this case, my 2nd sample works fine. But you said this script is not what you want. I thought that the relation between thread ID and message IDs may be different from my consideration. So I prepared a sample script for retrieving message IDs in a thread ID. Before you use this script, please do above your scenario. After this, please run this script, and retrieve message IDs and the thread ID. Please tell me the result and the message ID you want to add the label.
This script retrieves messages in a thread ID. messageId, from, to and subject are retrieved for the information of each message.
function myFunction() {
var result = [];
var thread = GmailApp.getInboxThreads();
var threadId = "";
thread.forEach(function(th) {
th.getMessages().forEach(function(msg) {
var mm = msg.getThread().getMessages();
if (mm.length > 1) {
var ids = {threadId: msg.getThread().getId()}
var mids = [];
mm.forEach(function(m) {
mids.push({
messageId: m.getId(),
from: m.getFrom(),
to: m.getTo(),
subject: m.getSubject()
});
});
ids.message = mids;
if (threadId != th.getId()) {
result.push(ids);
}
}
threadId = th.getId();
});
});
Logger.log(JSON.stringify(result))
}
Edit 4 :
This script adds a label to a replied message. This script supposes the following situation.
You receive an email from user "A" in Inbox. This is message "1". At this time, a thread is created.
You reply to user "A" for message "1". The replied message is message "2". This message is added to the created thread.
You receive an email from user "A" as the reply. This message is message "3". This message is also added to the created thread.
For above situation, this script adds a label to only message "2".
Script :
function myFunction() {
var label = "temp"; // Please input a label you want to use.
var userId = "me"; // If you use this script by yourself, userId is "me".
var thread = GmailApp.getInboxThreads(); // In this setting, all mails in Inbox are retrieved. If you want to use the special mails, please modify here.
var threadId = "";
thread.forEach(function(th) {
th.getMessages().forEach(function(msg) {
var mm = msg.getThread().getMessages();
if (mm.length > 1) {
var temp = [];
mm.forEach(function(m) {
var re = /<(\w.+)>/g;
var from = m.getFrom();
var to = m.getTo();
temp.push({
from: from.match(re) ? re.exec(from)[1] : from,
to: to.match(re) ? re.exec(to)[1] : to,
threadId: th.getId(),
messageId: m.getId()
});
});
if (temp.length > 1 && threadId != th.getId()) {
var ar = temp.filter(function(e){return temp[0].from == e.to});
if (ar.length > 0) {
if (ar.length > 1) ar.splice(1, ar.length - 1);
ar.forEach(function(e){
Gmail.Users.Messages.modify(
{"addLabelIds": [Gmail.Users.Labels.list(userId).labels.filter(function(e){return e.name == label})[0].id]},
userId,
e.messageId
);
Logger.log("Label '%s' was added to messageId '%s'.", label, e.messageId)
});
}
threadId = th.getId();
}
}
});
});
}
Note :
When you use this script, in this script, var thread = GmailApp.getInboxThreads(); is used for retrieving messages. This means that messages in Inbox are retrieved. If you want to retrieve in other places, please modify this.
Edit 5 :
function myFunction() {
var label = "temp"; // Please input a label you want to use.
var userId = "me"; // If you use this script by yourself, userId is "me".
var thread = GmailApp.getInboxThreads(); // In this setting, all mails in Inbox are retrieved. If you want to use the special mails, please modify here.
var threadId = "";
thread.forEach(function(th) {
th.getMessages().forEach(function(msg) {
var mm = msg.getThread().getMessages();
if (mm.length > 1) {
var temp = [];
mm.forEach(function(m) {
var re = /<(\w.+)>/g;
var from = m.getFrom();
var to = m.getTo();
temp.push({
from: from.match(re) ? re.exec(from)[1] : from,
to: to.match(re) ? re.exec(to)[1] : to,
threadId: th.getId(),
messageId: m.getId()
});
});
Logger.log("temp : %s", temp) // Added
if (temp.length > 1 && threadId != th.getId()) {
var ar = temp.filter(function(e){return temp[0].from == e.to});
Logger.log("ar : %s", ar) // Added
if (ar.length > 0) {
if (ar.length > 1) ar.splice(1, ar.length - 1);
ar.forEach(function(e){
Gmail.Users.Messages.modify(
{"addLabelIds": [Gmail.Users.Labels.list(userId).labels.filter(function(e){return e.name == label})[0].id]},
userId,
e.messageId
);
Logger.log("Label '%s' was added to messageId '%s'.", label, e.messageId)
});
}
threadId = th.getId();
}
}
});
});
}

Related

Adding a tag to an email file creates an error

I created a script that receives last minute emails if they do not contain a "a" tag and sends the content of the message to a function I called "ssfunction" and then adds the "a" tag to it
And this is the script I made:
const threads = GmailApp.search('-{label:a}');
for (const thread of threads) {
const messages = thread.getMessages();
const minuteAgo = new Date(Date.now() - 60000);
if (thread.getLastMessageDate() > minuteAgo) {
for (const message of messages) {
if (message.getDate() > minuteAgo) {
const result = ssfunction(message);
didUpload = result || didUpload;
}
}
thread.addLabel("a");
} else {
const result = ssfunction(messages[messages.length - 1]);
didUpload = result || didUpload;
thread.addeLabel("a");
}
But I get such an error:
TypeError: thread.addeLabel is not a function
Thank you so much for all the willingness to help
In your script, I thought that the method name of addeLabel is required to be modified to addLabel. I think that this is the reason of your error message. And, in the case of addLabel, the argument is GmailLabel object. When these points are reflected in your script, it becomes as follows.
From:
thread.addeLabel('a');
To:
var label = GmailApp.getUserLabelByName("a");
thread.addLabel(label);
Refernce:
addLabel(label)

Two App scripts running on Forms and Sheets, need to connect them both

I have an onboarding form that puts all the responses in a google sheet which has an app script running to add user to google admin and different groups by taking in values from the last row of the sheet. That works fine, it's just that I have to run the script every time the form is filled so I want to create a form trigger.
It made sense to create a form submit trigger on the app script attached to the google form and I added the library and script id of the other appscipt and pulled in a method from there like such
// Create a form submit installable trigger
// using Apps Script.
function createFormSubmitTrigger() {
// Get the form object.
var form = FormApp.getActiveForm();
// Since we know this project should only have a single trigger
// we'll simply check if there are more than 0 triggers. If yes,
// we'll assume this function was already run so we won't create
// a trigger.
var currentTriggers = ScriptApp.getProjectTriggers();
if(currentTriggers.length > 0)
return;
// Create a trigger that will run the onFormSubmit function
// whenever the form is submitted.
ScriptApp.newTrigger("onFormSubmit").forForm(form).onFormSubmit().create();
}
function wait(ms){
var start = new Date().getTime();
var end = start;
while(end < start + ms) {
end = new Date().getTime();
}
}
function onFormSubmit() {
wait(7000);
AddingUserAutomation.createUserFromSheets()
}
The trouble is I get the error
TypeError: Cannot read property 'getLastRow' of null
at createUserFromSheets(Code:43:19)
My createUserFromSheets function is taking the active sheet
function createUserFromSheets(){
let data = SpreadsheetApp.getActiveSheet();
let row = data.getLastRow();
let firstname = data.getRange(row,2).getValue();
let lastname = data.getRange(row,3).getValue();
... etc etc
}
I think it is unable to pull the getActiveSheet part that is why I had added the wait() function on formSubmit() but it still would not work.
Is there a way to solve this or a better way to do it?
function createWorkspaceUser(recentResponse) {
console.log("Creating account for:\n"+recentResponse[1]);
debugger;
var user = {"primaryEmail": recentResponse[0] + '.' + recentResponse[1] + '#' + recentResponse[3],
"name": {
"givenName": recentResponse[0],
"familyName": recentResponse[1]
},
"password": newPassword(),
};
try {
user = AdminDirectory.Users.insert(user);
console.log('User %s created with ID %s.', user.primaryEmail, user.id);
}catch(err) {
console.log('Failed with error %s', err.message);
}
}
I am doing it this way but it's running an error on primaryemail
Suggestion [NEW UPDATE]
As mentioned by RemcoE33
To have a more simplified setup, perhaps skip the library part and do all the scripting (bound script) in your Google Form itself.
Since we don't have the complete overview of your actual Google Form. See this sample below as a reference:
Google Form Script
function onFormSubmit() {
var form = FormApp.getActiveForm();
var count = 0;
var recentResponse = [];
var formResponses = form.getResponses();
for (var i in formResponses) {
count += 1;
var formResponse = formResponses[i];
var itemResponses = formResponse.getItemResponses();
for (var j = 0; j < itemResponses.length; j++) {
if(formResponses.length === count){ //Process only the recently submitted response
var itemResponse = itemResponses[j];
recentResponse.push(itemResponse.getResponse())
}
}
}
createWorkspaceUser(recentResponse);
}
function createWorkspaceUser(recentResponse){
var user = {"primaryEmail": recentResponse[0].replace(/\s/g, '') + '.' + recentResponse[1].replace(/\s/g, '') + '#' +recentResponse[3],
"name": {
"givenName": recentResponse[0],
"familyName": recentResponse[1]
},
"password":newPassword(),
};
try{
user = AdminDirectory.Users.insert(user);
Logger.log('User %s created with ID %s.', user.primaryEmail, user.id);
}catch (err) {
Logger.log('Failed with error %s', err.message);
}
console.log(user);
}
NOTE: You no longer need to build an on form submit trigger since the onFormSubmit() function will automatically run right after hitting the submit button.
Demonstration
1. Submit user data from sample form:
2. Test user account will be created on Workspace Admin Console Users:
Reference
https://developers.google.com/apps-script/reference/forms/form-response
https://developers.google.com/apps-script/guides/triggers

How to continue running the script even if a user exists in Google Group using google scripts?

I need help with Google groups. The code currently checks if a member already exists but it stop when it does find one. How can I modify the code to allow it to process the next row without stopping?
TIA!
function updateGroup() {
const s = SpreadsheetApp.openById("ID HERE");
const sheet_name = s.getSheetByName("REPORT HERE");
const sheet_data = sheet_name.getRange(2,1,sheet_name.getLastRow(),sheet_name.getLastColumn());
const sheet_dataVal = sheet_data.getValues();
for (var i = 0; i < sheet_dataVal.length-1; i++) {
var member_Email = sheet_dataVal[i][9]; // REWS Projects Email Address
var groupEmail = "GROUP EMAIL ADDRESS HERE";
var member_Role = "MEMBER";
var member_Type = "USER";
var group = GroupsApp.getGroupByEmail(groupEmail);
var comment = sheet_dataVal[i][13];
if (comment === "Member Added to Group" || comment === "Member already exists") {continue;}
var checkMembers = AdminDirectory.Members.list(groupEmail).members
for (var m in checkMembers) {
if (checkMembers[m].email == member_Email);
return sheet_name.getRange(i+2,14).setValue("Member already exists");
}
addNewMembersToGroup(member_Email,member_Role,groupEmail,i,sheet_name);
}
}
function addNewMembersToGroup(member_Email,member_Role,groupEmail,i,sheet_name) {
/* Member does not exists in group, add */
var addNewMember = {
kind: "admin#directory#member",
email: member_Email,
role: member_Role
};
AdminDirectory.Members.insert(addNewMember,groupEmail);
sheet_name.getRange(i+2,14).setValue("Member Added to Group");
}
When you are using a return, the execution of the function is stopped - hence the issue you are getting.
In order to fix this, you should remove the return and have the if statement like this:
if (checkMembers[m].email == member_Email);
sheet_name.getRange(i+2,14).setValue("Member already exists");
Reference
JavaScript return statement.

Need to Copy data from email and paste into google spreadsheet

There was two function wrote in that answer code, one is main and another one is extract details so its take two function, whenever ran the script its throwing error like getdate() not define so i just make as one function as main, now the data tracked automatically into sheet but its reading only first thread which is unread label. if the label having 23 thread , the first thread only repeating as 23 times. even I Have changed threads.messages(0) tracking only first thread which is already read thread, not read and track unread thread. Could you help me
function main(){
var query = {'q':'label:"Sanmina EDI Failed Concurrent Jobs Alert" is:UNREAD'};
var threads = Gmail.Users.Messages.list(userId='me', q=query);
for(i in threads.messages){
var threadIds = threads.messages[0].threadId;
var message = GmailApp.getMessageById(threadIds);
extractDetails(message);
GmailApp.markMessageRead(message);
}
function extractDetails(message)
{
var dateTime = message.getDate();
var bodyContents = 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>0)
{
var out="Need to create SR"
}
else
{
var out="Printing output file"
}
var activeSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
activeSheet.autoResizeRows(1, 2);
activeSheet.appendRow([dateTime, bodyContents, out]);
}
}
[enter image description here][1]
Sanmina EDI Failed Concurrent Jobs Alert - subject same name for label
Production Workflow Mailer
May 26, 2017, 7:30 PM
Request Id Program Name Status Requested By
---------- ------------------------------------------------------------ -------- 813511350 Sanmina EDI 850/860 Inbound PO/Change Tabular Report Warning NERODRIG
Try using the Gmail API to search the threads:
function main(){
var query = {'q':'label:"Sanmina EDI Failed Concurrent Jobs Alert" is:UNREAD'};
var threads = Gmail.Users.Messages.list(userId='me', q=query);
for(i in threads.messages){
var threadIds = threads.messages[i].threadId;
var message = GmailApp.getMessageById(threadIds);
extractDetails(message);
GmailApp.markMessageRead(message);
}
}
function extractDetails(message){
var dateTime = message.getDate();
var bodyContents = message.getPlainBody();
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([dateTime, bodyContents, out]);
}
In case you only want the last message, use threads.messages[0] instead of i.
More information:
List method

Inconsistencies between app scripts GmailApp.search and the search in gmail interface

I'm trying to build a google app script to import mail received from an online form to a spreadsheet.
I am using two labels: One "to_process" is added by a gmail filter, the other one "processed" is added by this script after the email was added to the sheet.
I am searching for all emails that have "to_process" but not "processed" using the search query 'label:to_process !label:processed in:all'
I got it working partially (see the core of the script below)
I'm running the script using the script editor run function.
The problem is that using the same query in gmail interface i get more than 100 emails, but in the log of the script I get 6, and they are all processed.
Am I missing something?
function extractInfo() {
var step = 30;
var max = 500;
var currentStep = 0;
while(max--) {
var threads = GmailApp.search('label:to_process !label:processed in:all', currentStep++ * step, step);
if(threads.length == 0) break;
Logger.log("-------- found threads: " + threads.length);
var threadId = threads.length;
while(threadId--) {
var thread = threads[threadId];
thread.refresh();
if(hasLabel(thread, "processed")) {
Logger.log("was processed: " + thread.getPermalink())
continue;
}
if(!hasLabel(thread, "to_process")) {
Logger.log("isn't mark to process: " + thread.getPermalink())
continue;
}
var messages = thread.getMessages();
var messageId = messages.length;
while(messageId--) {
var message = messages[messageId];
var row = extractMessageData(message);
sheet.appendRow(row);
GmailApp.markMessageRead(message);
}
threads[threadId].addLabel(processedLabel);
}
}
}
function hasLabel(thread, name) {
var labels = thread.getLabels();
var l = labels.length;
while(l--) {
if(labels[l].getName() == name) {
return true;
}
}
return false;
}
After much trail and error I partially figured this out.
What I see in gmail ui is in fact message, and not threads. But handling labels is a per thread thing.
I simply pulled all message of all threads from a given label, and then processed theses.
If a thread has a label "processed" it doesn't mean all it's messages were processed, which is a problem.
There are still inconsistencies regarding the number of messages i see in the UI and what I get using the API though.