How to adapt script for different 'from' addresses and folder names? - google-apps-script

I have a Google Apps Script which searches the inbox for messages from a certain email address, adds a new label and then archives the email so as to remove the inbox tag. I'm wondering, is there an easy way to apply the script to many different email addresses and apply different filing labels without making an individual script or having a bloated single script with all the different email addresses in it?
function _getFilingLabel() {
var label_text = "**folder name for filing**";
var label = GmailApp.getUserLabelByName(label_text);
if (label == null) {
var label = GmailApp.createLabel(label_text);
}
return label;
}
function addfilelabel() {
var label = _getFilingLabel();
var threads = GmailApp.search('from:(**email address here**) label:inbox older_than:30d');
for (var i = 0; i < threads.length; i++) {
label.addToThread(threads[i]);
}
}
/**
* SCAN THROUGH THE "**folder name for filing**" label and unlabel any items that aren't currently in the inbox
*/
function removeinboxlabel() {
// Every thread in label is archived to remove the inbox label.
var threads = GmailApp.search('label:"**folder name for filing**"');
for (var i = 0; i < threads.length; i++) {
threads[i].moveToArchive();
}
}
function incorrectfiled() {
// Checks for items incorrectly filed in folder with activity newer than 30d.
var threads = GmailApp.search('label:"**folder name for filing**" newer_than:30d');
for (var i = 0; i < threads.length; i++) {
threads[i].moveToInbox();
}
}

The first step you can take toward making your script re-usable is to replace your hard-coded values with parameters. For example, here's addfilelabel() with parameters for from_address and label_text, with the balance of the functions following in a snippet:
function addfilelabel(from_address, label_text) {
var label = _getFilingLabel(label_text);
var threads = GmailApp.search('from:(%FROM%) label:inbox older_than:30d'
.replace('%FROM%',from_address));
for (var i = 0; i < threads.length; i++) {
label.addToThread(threads[i]);
}
}
function _getFilingLabel(label_text) {
var label = GmailApp.getUserLabelByName(label_text);
if (label == null) {
var label = GmailApp.createLabel(label_text);
}
return label;
}
function addfilelabel(from_address, label_text) {
var label = _getFilingLabel(label_text);
var threads = GmailApp.search('from:(%FROM%) label:inbox older_than:30d'
.replace('%FROM%',from_address));
for (var i = 0; i < threads.length; i++) {
label.addToThread(threads[i]);
}
}
/**
* Scan the given label and archive any items that aren't currently in the inbox
*/
function removeinboxlabel(label_text) {
// Every thread in label is archived to remove the inbox label.
var threads = GmailApp.search('label:"%LABEL%"'
.replace('%LABEL%',label_text));
for (var i = 0; i < threads.length; i++) {
threads[i].moveToArchive();
}
}
function incorrectfiled(label_text) {
// Checks for items incorrectly filed in folder with activity newer than 30d.
var threads = GmailApp.search('label:"%LABEL%" newer_than:30d'
.replace('%LABEL%',label_text));
for (var i = 0; i < threads.length; i++) {
threads[i].moveToInbox();
}
}
Note how from_address is placed into the search string using the JavaScript String.replace() method to fill in a placeholder. There's no magic with the placeholder string '%FROM%', this is simply a convention intended to make the placeholder stand out and to decrease the likelihood of accidentally replacing the wrong text.
Now you can call the function like this, which is one simple way to reuse the basic code you've written:
function do_addfilelabel() {
addfilelabel("user1#example.com", "from-user1");
addfilelabel("user2#example.com", "from-user2");
addfilelabel("user3#example.com", "from-user3");
}
From there, you could progress to have a user interface in a Web Application, say. The Web Application could have a simple user interface allowing you to enter an email address and label, then pass those to your server-side function(s) as parameters with google.script.run.

Related

Unable to get this "tagging unanswered email" script to work

The following is a script that I found online to tag all the unanswered emails. It works for one of my gmail accounts, however when I shared it to another account and run it, it returns nothing every single time, even though there are unanswered emails within that time range. I then tried copy and paste the codes into a new project, however still wouldn't work.
Anyone has any ideas?
Thanks in advance!
/*
* This script goes through your Gmail Inbox and finds recent emails where you
* were the last respondent. It applies a nice label to them, so you can
* see them in Priority Inbox or do something else.
*
* To remove and ignore an email thread, just remove the unrespondedLabel and
* apply the ignoreLabel.
*
* This is most effective when paired with a time-based script trigger.
*
* For installation instructions, read this blog post:
* http://jonathan-kim.com/2013/Gmail-No-Response/
*/
// Edit these to your liking.
var unrespondedLabel = 'No Response',
ignoreLabel = 'Ignore No Response',
minDays = 0.125,
maxDays = 5;
function main() {
processUnresponded();
cleanUp();
}
function processUnresponded() {
var threads = GmailApp.search('is:sent from:me -in:chats older_than:' + minDays + 'd newer_than:' + maxDays + 'd'),
numUpdated = 0,
minDaysAgo = new Date();
minDaysAgo.setDate(minDaysAgo.getDate() - minDays);
// Filter threads where I was the last respondent.
for (var i = 0; i < threads.length; i++) {
var thread = threads[i],
messages = thread.getMessages(),
lastMessage = messages[messages.length - 1],
lastFrom = lastMessage.getFrom(),
lastMessageIsOld = lastMessage.getDate().getTime() < minDaysAgo.getTime();
if (isFromMe(lastFrom) && lastMessageIsOld && !threadHasLabel(thread, ignoreLabel)) {
markUnresponded(thread);
numUpdated++;
}
}
Logger.log('Updated ' + numUpdated + ' messages.');
}
function isFromMe(fromAddress) {
var addresses = getEmailAddresses();
for (i = 0; i < addresses.length; i++) {
var address = addresses[i],
r = RegExp(address, 'i');
if (r.test(fromAddress)) {
return true;
}
}
return false;
}
function getEmailAddresses() {
var me = Session.getActiveUser().getEmail(),
emails = GmailApp.getAliases();
emails.push(me);
return emails;
}
function threadHasLabel(thread, labelName) {
var labels = thread.getLabels();
for (i = 0; i < labels.length; i++) {
var label = labels[i];
if (label.getName() == labelName) {
return true;
}
}
return false;
}
function markUnresponded(thread) {
var label = getLabel(unrespondedLabel);
label.addToThread(thread);
}
function getLabel(labelName) {
var label = GmailApp.getUserLabelByName(labelName);
if (label) {
Logger.log('Label exists.');
} else {
Logger.log('Label does not exist. Creating it.');
label = GmailApp.createLabel(labelName);
}
return label;
}
function cleanUp() {
var label = getLabel(unrespondedLabel),
iLabel = getLabel(ignoreLabel),
threads = label.getThreads(),
numExpired = 0,
twoWeeksAgo = new Date();
twoWeeksAgo.setDate(twoWeeksAgo.getDate() - maxDays);
if (!threads.length) {
Logger.log('No threads with that label');
return;
} else {
Logger.log('Processing ' + threads.length + ' threads.');
}
for (i = 0; i < threads.length; i++) {
var thread = threads[i],
lastMessageDate = thread.getLastMessageDate();
// Remove all labels from expired threads.
if (lastMessageDate.getTime() < twoWeeksAgo.getTime()) {
numExpired++;
Logger.log('Thread expired');
label.removeFromThread(thread);
iLabel.removeFromThread(thread);
} else {
Logger.log('Thread not expired');
}
}
Logger.log(numExpired + ' unresponded messages expired.');
}
The Gmail search operator "older_than" does not support decimals, so you cannot use "0.125" in this case. Make sure you use an integer number/day. The script will not return errors, but the search will not work. More info about the Gmail search operators at https://support.google.com/mail/answer/7190?hl=en

gmail app script cleaninbox modding

Sorry, i'm not a programmer,
I'm using this gmail app script (CLEANINBOX) and it works great in roder to keep my inbox clean.
As I need to use INBOX app (mobile) and GMAIL app (desktop) at the same time I need to implement this script in order to avoid that PINNED messages in INBOX get archieved.
I inserted a condition in the IF sequence and it does not work
After struggling a bit I realized (correct me if I'm wrong) that the following code is not working becouse !thread.getLabels()=='PINNED') IS NOT BOOLEAN
Can anybody point me to the correct code?
function cleanInbox() {
var threads = GmailApp.getInboxThreads();
for (var i = 0; i < threads.length; i++) {
var thread=threads[i];
if (!thread.hasStarredMessages() && !thread.isUnread() && !thread.getLabels()=='PINNED') {
GmailApp.moveThreadToArchive(threads[i]);
}
}
}
Ok it was much easyer then expected...
I just needed to narrow down the number of threads to work with, and i did it just excluding those with "pinned" label
var threads = GmailApp.search('in:inbox -label:pinned')
solved
thanks for input
The statement !thread.getLabels()=='PINNED' is boolean (as the operand == outputs true or false). I think your problem is that thread.getLabels() does not return a string and therefore it will never be equal to 'PINNED'
EDIT:
The getLabels() method return value is GmailLabel[]. You can iterate over the labels and check your condition by adding this code:
for (var i = 0; i < threads.length; i++) {
var thread=threads[i];
if (!thread.hasStarredMessages() && !thread.isUnread()) {
var labels = thread.getLabels();
var isPinned = false;
for (var j = 0; i < labels.length; i++) {
if (labels[j].getName() == "PINNED"){
isPinned = true;
break;
}
if (!isPinned){
GmailApp.moveThreadToArchive(threads[i]);
}
}

Labeling Gmail message (not the whole thread) with Google Apps Script

Is it possible to search to messages with the label 'Apps script queue' and give just these specific messages (not the whole thread) a new label?
When I use GmailApp.search('label:Apps script queue') I get the requested messages but when I assign a new label to these messages, all the other messages of the thread (on other places in the mailbox) will get the same label. And that is not what I want.
This code does not return an error while adding a label to a specific message in a thread and if you use thread list method you'll see that it is only placed in the specific messageID(treated separately). But once your UI(Gmail site) is in conversation mode, it will be viewable in both labels.
function searchMail(){
var threads = GmailApp.search("SOME SEARCH");
Logger.log(threads.length);
listLabel('me');
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
Logger.log(messages.length);
for (var j = 0; j < messages.length; j++){
if (messages[j].isInInbox()){
Logger.log('me' + 'id msg: ' + messages[j].getId());
//Add label to the first reply
addLabel('me',messages[1].getId());
}
else{
Logger.log('me' + 'id msg: ' + messages[j].getId() +" not in inbox");
}
}
}
}
function addLabel(userId, messageId){
var resource = {addLabelIds: ["Label_6"]}
Gmail.Users.Messages.modify(resource, userId, messageId);
}
In Gmail, labels are applied to a thread and cannot be applied to a single email message of a thread.
You can however apply stars / colors to individual messages.
This is an old thread, but for anybody who might be reading it like me, maybe this will save you some time:
function getLabelMap() {
var allLabels = Gmail.Users.Labels.list('me');
var labelMap = [];
for (var label of allLabels.labels) {
labelMap[label.name] = label.id;
}
return labelMap;
}
var labelMap = getLabelMap();
function getLabel(labelName) {
return labelMap[labelName];
}
function labelMessage(messageID, labelName) {
var labelID = getLabel(labelName);
var labelRequest = {addLabelIds: [labelID]};
var subject = GmailApp.getMessageById(messageID).getSubject();
if (labelID != null) {
Logger.log("Labelling as %s: %s", labelName, subject);
Gmail.Users.Messages.modify(labelRequest, 'me', messageID);
} else {
Logger.log("Label not found: %s", labelName);
}
}
function unlabelMessage(messageID, labelName) {
var labelID = getLabel(labelName);
var labelRequest = {removeLabelIds: [labelID]};
var subject = GmailApp.getMessageById(messageID).getSubject();
if (labelID != null) {
Logger.log("Removing label %s: %s", labelName, subject);
Gmail.Users.Messages.modify(labelRequest, 'me', messageID);
} else {
Logger.log("Label not found: %s", labelName);
}
}
function reLabel () {
var messagesToRelabel = Gmail.Users.Messages.list('me', {'q':'label:Apps-script-queue'}).messages || [];
// Loop through each message (not by thread), using the Advanced Gmail Service (full GMail API in a Google Script).
messagesToRelabel.forEach(function (messageToRelabel){
unlabelMessage(messageToRelabel.id, "Apps script queue");
labelMessage(messageToRelabel.id, "New label");
});
}
Not asked for by the OP, but may be helpful for others who are trying to do "advanced filtering / labeling" using the GMail API:
function getMessageHeader(messageID, headerField) {
var messageInfo = Gmail.Users.Messages.get('me', messageID, {'format':'METADATA', 'metadataHeaders':[headerField]});
if (messageInfo.payload.headers) {
return messageInfo.payload.headers[0].value;
} else {
return null;
}
}
The above lets you filter on header info, e.g. I use it to check whether X-Uniform-Type-Identifier is equal to com.apple.mail-note to automatically flag old Apple Notes for deletion.

Check if current user is the administrator of a certain Google group

I want to go through all the Google groups I am a member of and get the list of all the users of each group :
var list = GroupsApp.getGroups();
for(var i = 0; i< list.length; i++){
for(var key in headerObj){
var text = "";
if(key == "users"){
var tab = list[i].getUsers();
if(tab.length > 0){
text = tab[0].getEmail();
for(var j = 1; j < tab.length; j++){
text += ", " + tab[j].getEmail();
}
}
headerObj[key].push(text);
}
}
}
But I always get this Exception :
You do not have permission to view the member list for the group: "group email"
Is there a way to go through all the Google groups of which, I am the administrator ?
Unfortunatly such a thing is not possible there is however the workaround of a try catch:
function myFunction() {
var allGroups = GroupsApp.getGroups();
for (var i in allGroups){
try {
var users = allGroups[i].getUsers();
for (var j in users){
Logger.log(users[j]);
}
}
catch (e) { }
}
}

Google Apps Script: copy header / footer

I try to copy the meta data of an document in my Google drive to another. Like Page dimensions, viewers, editors and the content of header / footer. But the header is not copied. Anyone an idea why?
Addtional info:
appendElementToDoc only search for append Methods an call them, e.g. appendParagraph. This is working great to copy the content of the document.
/**
* Copy elements to new doc
*/
function appendElementToDoc(bulk, element) {
var tName = underscoreToCamelCase(element.getType() + "");
Logger.log(tName + "");
try {
bulk["append" + tName](element);
}
catch(err) {
Logger.log(err + "");
}
return bulk;
}
/**
* Transform typename to functio name
*/
function underscoreToCamelCase(type) {
type = type.toLowerCase();
var tName = type.charAt(0).toUpperCase() + type.slice(1);
var parts = tName.split("_");
if(parts.length == 2) {
tName = parts[0] + parts[1].charAt(0).toUpperCase() + parts[1].slice(1);
}
return tName;
}
/**
* Getting bulk document to insert content
*
* #param Document
* #return Document
*/
function getBulkDocument(template) {
var bulk = DocumentApp.create("Bulk Letter");
bulk.setMarginBottom(template.getMarginBottom());
bulk.setMarginLeft(template.getMarginLeft());
bulk.setMarginRight(template.getMarginRight());
bulk.setMarginTop(template.getMarginTop());
bulk.setPageHeight(template.getPageHeight());
bulk.setPageWidth(template.getPageWidth());
var header = bulk.addHeader();
for (var i = 0; i < template.getHeader().getNumChildren(); i++) {
appendElementToDoc(header, template.getHeader().getChild(i).copy());
}
var footer = bulk.addFooter();
for (var i = 0; i < template.getFooter().getNumChildren(); i++) {
appendElementsToDoc(footer, template.getFooter().getChild(i).copy());
}
var editors = template.getEditors();
for (var i = 0; i < editors.length; i++) {
bulk.addEditor(editors[i])
}
var viewers = template.getViewers();
for (var i = 0; i < editors.length; i++) {
bulk.addViewer(viewers[i])
}
//move to folder
DocsList.getFileById(bulk.getId()).addToFolder(DocsList.getFolder("tmp"));
return bulk;
}
I did call the function with a fixed documentID, after calling getBulkDocument the correct way it works. But better to use this before:
if(!bulk.getFooter()) {
var footer = bulk.addFooter();
} else {
var footer = bulk.getFooter();
}
The full example, to copy will follow on my blog...