Google Script for Gmail not consistent - google-apps-script

I have a filter that adds the "unprocessed" label on all incoming emails.
Then a Google Script searches every minute for any email threads that have the "unprocessed" label, processes the messages, and conditionally apply a label to the corresponding thread.
I don't know what I have done wrong, but only SOME of the processed threads get the label. And it works randomly... For example only 3 out of 6 threads got the label, or 1 out of 3.
I have to re-apply the "unprocessed" label, and just run the script again to fix them.
function processGmail() {
var startTime = new Date().getTime();
var mailerRegex = /X-Mailer:(.*)/g;
var scannerLabel = GmailApp.getUserLabelByName("Scanner");
var unprocessedLabel = GmailApp.getUserLabelByName("unprocessed");
var countMessages = 0;
GmailApp.search("label:unprocessed").forEach(
function(emailThread) {
emailThread.getMessages().forEach(
function(message) {
var raw = message.getRawContent();
var result;
var doReturn = false;
while((matches = mailerRegex.exec(raw)) !== null) {
if (matches.some(function(match){return match.indexOf('Canon MFP') >= 0;})) {
emailThread.addLabel(scannerLabel);
emailThread.moveToArchive();
doReturn = true;
break;
}
}
emailThread.removeLabel(unprocessedLabel);
++countMessages;
if (doReturn) {
return;
}
}
);
}
);
var endTime = new Date().getTime();
Logger.log("Processed " + countMessages + " in " + (endTime-startTime) + "ms.");
}

Turns out the bug was Javascript related.
I had forgotten that the regex.exec needs to be looped until a null is returned, only then it will start a-new for a new input.
The fix was removing break :)

Related

Is there any way to see the names of a website's network requests with Google apps scripts?

So here's what I'm trying to do:
There's a website called Torah Anytime (https://www.torahanytime.com/) which publishes audio files (I guess you can call them podcasts, the website refers to them as shiurim, shiur being hebrew for song, or in this case, audio) on a daily basis. I would like to create a script that downloads the audio of specific speakers and then emails those files to me. The way I'm accomplishing this is with Google Apps Scripts. Torah Anytime allows you to follow specific speakers and to get email notifications when a speaker you're following puts out a new podcast. Here is the code that I have so far:
function main() {
var emails = getemails();
for (var i = 0; i < emails.length; i++) {
var email = emails[i].getMessages();
if (email[0].getFrom() == "TorahAnytime Following <following#torahanytime.com>"){
var title = getTitle(email);
var shiurID = getShiurID(email);
var downloadLink = "https://dl.torahanytime.com/audio/" + shiurID;
var shiur = downloadShiur(downloadLink);
shiur.setName(title);
var emailSent = emailShiur(shiur);
if (emailSent) {email[0].moveToTrash();
Logger.log("Email moved to Trash");}
}
}
}
function getemails() {
var label = GmailApp.getUserLabelByName("TA Speeches");
return label.getThreads();
}
function getTitle(email) {
body = email[0].getPlainBody();
var begIndex = body.indexOf("from") + 4;
var endIndex = body.indexOf("on ");
var title = body.substring(begIndex, endIndex).toLowerCase().replaceAll(" ", "-").replace(/(\r\n|\n|\r)/gm, "-");
begIndex = body.indexOf("called ") + 7;
endIndex = body.indexOf(" [");
title += "-" + body.substring(begIndex, endIndex).toLowerCase().replaceAll(" ", "-").replace(/(\r\n|\n|\r)/gm, "-") + ".mp3";
return title;
}
function getShiurID(email) {
body = email[0].getPlainBody();
var begIndex = body.indexOf("[") + 1;
var endIndex = body.indexOf("]");
var link = body.substring(begIndex, endIndex).replaceAll("?v", "?a");
console.log(link);
var mainLink = UrlFetchApp.fetch(link);
//here I somehow need to get the link being used to stream that particular audio file
}
function getIDName(email) {
body = email[0].getPlainBody();
var begIndex = body.indexOf("ID ") + 3;
var endIndex = body.indexOf(" and");
return body.substring(begIndex, endIndex);
}
function downloadShiur(downloadLink) {
var audio = UrlFetchApp.fetch(downloadLink);
return audio.getBlob().getAs('audio/mp3');
}
function emailShiur(shiur) {
const maxFileSize = 26214400;
if (shiur.getBytes().length <= maxFileSize) {
MailApp.sendEmail("[Email addressed removed]", "TA Shiur (File)", "Enjoy!", {
attachments: [shiur],
name: 'Automatic Emailer Script'
});
return true;
} else {
MailApp.sendEmail("[Email addressed removed]", "TA Shiur (File)", "Error, File too large to email", {
name: 'Automatic Emailer Script'
});
return false;
}
}
My issue is that the URL to download the file is not in the HTML, so I don't know how to get to it using GAS. If you use chrome's dev-tools, you can see the URL right there in the network tab Example of output I see that I want to get. Does anyone know of any way that I can get the information that I see in chrome's dev-tools network tab (the name's of the URLs being received) using GAS? Thank you!

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

Google AppScript dies with "Service Unavailable: Docs"

I wrote an app script that should break down a wall of text into separate paragraphs.
function onOpen() {
DocumentApp.getUi()
.createMenu('Formatting tool')
.addItem('Make Paragraphs', 'breakIntoParagraphs')
.addToUi();
}
function breakIntoParagraphs() {
var body = DocumentApp.getActiveDocument().getBody();
var counter = 0;
body.replaceText("\\v\\v+", "°"); // the ° is more convenient to handle
var rangeElement = body.findText("°");
while (rangeElement != null) {
var start = rangeElement.getStartOffset();
var paragraph = rangeElement.getElement().getParent();
var childIndex = body.getChildIndex(paragraph);
var endRangeElement = body.findText("°", rangeElement);
if (endRangeElement != null) {
var end = endRangeElement.getStartOffset();
var endParagraph = endRangeElement.getElement().getParent();
var endChildIndex = body.getChildIndex(endParagraph);
if ( childIndex != endChildIndex) {
Logger.log("this spans paragraphs!"); // deal with this case later
}
Logger.log(paragraph.asText());
var text = body.editAsText().deleteText(start, end - 1 ); // -1, so the concluding ° remains
Logger.log("deleted text: \"" + text + "\"");
var newParagraph = body.insertParagraph(childIndex, text);
newParagraph.editAsText.replaceText("°", ""); // remove markers
}
rangeElement = body.findText("°", rangeElement);
counter++;
if (counter > 2) {
break;
}
}
}
Unfortunately, it gives me an ugly red warning "Service unavailable: Docs". In the process of writing this, I learned that this means as much as "something fishy happened, and you have to figure out what that is, yourself." That can be timeouts, complex regular expressions, infinite loops (which give timeouts, too) etc. Google's issue tracking system has several of those.
Now I tried to avoid every complex or non-standard thing, and even made sure to break the loop in case of too many repetitions, but I still get the "Service unavailable: Docs". What could be causing this, and how can I fix it?

Can Google apps script be used to randomize page order on Google forms?

Update #2: Okay, I'm pretty sure my error in update #1 was because of indexing out of bounds over the array (I'm still not used to JS indexing at 0). But here is the new problem... if I write out the different combinations of the loop manually, setting the page index to 1 in moveItem() like so:
newForm.moveItem(itemsArray[0][0], 1);
newForm.moveItem(itemsArray[0][1], 1);
newForm.moveItem(itemsArray[0][2], 1);
newForm.moveItem(itemsArray[1][0], 1);
newForm.moveItem(itemsArray[1][1], 1);
newForm.moveItem(itemsArray[1][2], 1);
newForm.moveItem(itemsArray[2][0], 1);
...
...I don't get any errors but the items end up on different pages! What is going on?
Update #1:: Using Sandy Good's answer as well as a script I found at this WordPress blog, I have managed to get closer to what I needed. I believe Sandy Good misinterpreted what I wanted to do because I wasn't specific enough in my question.
I would like to:
Get all items from a page (section header, images, question etc)
Put them into an array
Do this for all pages, adding these arrays to an array (i.e: [[all items from page 1][all items from page 2][all items from page 3]...])
Shuffle the elements of this array
Repopulate a new form with each element of this array. In this way, page order will be randomized.
My JavaScript skills are poor (this is the first time I've used it). There is a step that produces null entries and I don't know why... I had to remove them manually. I am not able to complete step 5 as I get the following error:
Cannot convert Item,Item,Item to (class).
"Item,Item,Item" is the array element containing all the items from a particular page. So it seems that I can't add three items to a page at a time? Or is something else going on here?
Here is my code:
function shuffleForms() {
var itemsArray,shuffleQuestionsInNewForm,fncGetQuestionID,
newFormFile,newForm,newID,shuffle, sections;
// Copy template form by ID, set a new name
newFormFile = DriveApp.getFileById('1prfcl-RhaD4gn0b2oP4sbcKaRcZT5XoCAQCbLm1PR7I')
.makeCopy();
newFormFile.setName('AAAAA_Shuffled_Form');
// Get ID of new form and open it
newID = newFormFile.getId();
newForm = FormApp.openById(newID);
// Initialize array to put IDs in
itemsArray = [];
function getPageItems(thisPageNum) {
Logger.log("Getting items for page number: " + thisPageNum );
var thisPageItems = []; // Used for result
var thisPageBreakIndex = getPageItem(thisPageNum).getIndex();
Logger.log( "This is index num : " + thisPageBreakIndex );
// Get all items from page
var allItems = newForm.getItems();
thisPageItems.push(allItems[thisPageBreakIndex]);
Logger.log( "Added pagebreak item: " + allItems[thisPageBreakIndex].getIndex() );
for( var i = thisPageBreakIndex+1; ( i < allItems.length ) && ( allItems[i].getType() != FormApp.ItemType.PAGE_BREAK ); ++i ) {
thisPageItems.push(allItems[i]);
Logger.log( "Added non-pagebreak item: " + allItems[i].getIndex() );
}
return thisPageItems;
}
function shuffle(array) {
var currentIndex = array.length, temporaryValue, randomIndex;
Logger.log('shuffle ran')
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
function shuffleAndMove() {
// Get page items for all pages into an array
for(i = 2; i <= 5; i++) {
itemsArray[i] = getPageItems(i);
}
// Removes null values from array
itemsArray = itemsArray.filter(function(x){return x});
// Shuffle page items
itemsArray = shuffle(itemsArray);
// Move page items to the new form
for(i = 2; i <= 5; ++i) {
newForm.moveItem(itemsArray[i], i);
}
}
shuffleAndMove();
}
Original post: I have used Google forms to create a questionnaire. For my purposes, each question needs to be on a separate page but I need the pages to be randomized. A quick Google search shows this feature has not been added yet.
I see that the Form class in the Google apps script has a number of methods that alter/give access to various properties of Google Forms. Since I do not know Javascript and am not too familiar with Google apps/API I would like to know if what I am trying to do is even possible before diving in and figuring it all out.
If it is possible, I would appreciate any insight on what methods would be relevant for this task just to give me some direction to get started.
Based on comments from Sandy Good and two SE questions found here and here, this is the code I have so far:
// Script to shuffle question in a Google Form when the questions are in separate sections
function shuffleFormSections() {
getQuestionID();
createNewShuffledForm();
}
// Get question IDs
function getQuestionID() {
var form = FormApp.getActiveForm();
var items = form.getItems();
arrayID = [];
for (var i in items) {
arrayID[i] = items[i].getId();
}
// Logger.log(arrayID);
return(arrayID);
}
// Shuffle function
function shuffle(a) {
var j, x, i;
for (i = a.length; i; i--) {
j = Math.floor(Math.random() * i);
x = a[i - 1];
a[i - 1] = a[j];
a[j] = x;
}
}
// Shuffle IDs and create new form with new question order
function createNewShuffledForm() {
shuffle(arrayID);
// Logger.log(arrayID);
var newForm = FormApp.create('Shuffled Form');
for (var i in arrayID) {
arrayID[i].getItemsbyId();
}
}
Try this. There's a few "constants" to be set at the top of the function, check the comments. Form file copying and opening borrowed from Sandy Good's answer, thanks!
// This is the function to run, all the others here are helper functions
// You'll need to set your source file id and your destination file name in the
// constants at the top of this function here.
// It appears that the "Title" page does not count as a page, so you don't need
// to include it in the PAGES_AT_BEGINNING_TO_NOT_SHUFFLE count.
function shuffleFormPages() {
// UPDATE THESE CONSTANTS AS NEEDED
var PAGES_AT_BEGINNING_TO_NOT_SHUFFLE = 2; // preserve X intro pages; shuffle everything after page X
var SOURCE_FILE_ID = 'YOUR_SOURCE_FILE_ID_HERE';
var DESTINATION_FILE_NAME = 'YOUR_DESTINATION_FILE_NAME_HERE';
// Copy template form by ID, set a new name
var newFormFile = DriveApp.getFileById(SOURCE_FILE_ID).makeCopy();
newFormFile.setName(DESTINATION_FILE_NAME);
// Open the duplicated form file as a form
var newForm = FormApp.openById(newFormFile.getId());
var pages = extractPages(newForm);
shuffleEndOfPages(pages, PAGES_AT_BEGINNING_TO_NOT_SHUFFLE);
var shuffledFormItems = flatten(pages);
setFormItems(newForm, shuffledFormItems);
}
// Builds an array of "page" arrays. Each page array starts with a page break
// and continues until the next page break.
function extractPages(form) {
var formItems = form.getItems();
var currentPage = [];
var allPages = [];
formItems.forEach(function(item) {
if (item.getType() == FormApp.ItemType.PAGE_BREAK && currentPage.length > 0) {
// found a page break (and it isn't the first one)
allPages.push(currentPage); // push what we've built for this page onto the output array
currentPage = [item]; // reset the current page to just this most recent item
} else {
currentPage.push(item);
}
});
// We've got the last page dangling, so add it
allPages.push(currentPage);
return allPages;
};
// startIndex is the array index to start shuffling from. E.g. to start
// shuffling on page 5, startIndex should be 4. startIndex could also be thought
// of as the number of pages to keep unshuffled.
// This function has no return value, it just mutates pages
function shuffleEndOfPages(pages, startIndex) {
var currentIndex = pages.length;
// While there remain elements to shuffle...
while (currentIndex > startIndex) {
// Pick an element between startIndex and currentIndex (inclusive)
var randomIndex = Math.floor(Math.random() * (currentIndex - startIndex)) + startIndex;
currentIndex -= 1;
// And swap it with the current element.
var temporaryValue = pages[currentIndex];
pages[currentIndex] = pages[randomIndex];
pages[randomIndex] = temporaryValue;
}
};
// Sourced from elsewhere on SO:
// https://stackoverflow.com/a/15030117/4280232
function flatten(array) {
return array.reduce(
function (flattenedArray, toFlatten) {
return flattenedArray.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
},
[]
);
};
// No safety checks around items being the same as the form length or whatever.
// This mutates form.
function setFormItems(form, items) {
items.forEach(function(item, index) {
form.moveItem(item, index);
});
};
I tested this code. It created a new Form, and then shuffled the questions in the new Form. It excludes page breaks, images and section headers. You need to provide a source file ID for the original template Form. This function has 3 inner sub-functions. The inner functions are at the top, and they are called at the bottom of the outer function. The arrayOfIDs variable does not need to be returned or passed to another function because it is available in the outer scope.
function shuffleFormSections() {
var arrayOfIDs,shuffleQuestionsInNewForm,fncGetQuestionID,
newFormFile,newForm,newID,items,shuffle;
newFormFile = DriveApp.getFileById('Put the source file ID here')
.makeCopy();
newFormFile.setName('AAAAA_Shuffled_Form');
newID = newFormFile.getId();
newForm = FormApp.openById(newID);
arrayOfIDs = [];
fncGetQuestionID = function() {
var i,L,thisID,thisItem,thisType;
items = newForm.getItems();
L = items.length;
for (i=0;i<L;i++) {
thisItem = items[i];
thisType = thisItem.getType();
if (thisType === FormApp.ItemType.PAGE_BREAK ||
thisType === FormApp.ItemType.SECTION_HEADER ||
thisType === FormApp.ItemType.IMAGE) {
continue;
}
thisID = thisItem.getId();
arrayOfIDs.push(thisID);
}
Logger.log('arrayOfIDs: ' + arrayOfIDs);
//the array arrayOfIDs does not need to be returned since it is available
//in the outermost scope
}// End of fncGetQuestionID function
shuffle = function() {// Shuffle function
var j, x, i;
Logger.log('shuffle ran')
for (i = arrayOfIDs.length; i; i--) {
j = Math.floor(Math.random() * i);
Logger.log('j: ' + j)
x = arrayOfIDs[i - 1];
Logger.log('x: ' + x)
arrayOfIDs[i - 1] = arrayOfIDs[j];
arrayOfIDs[j] = x;
}
Logger.log('arrayOfIDs: ' + arrayOfIDs)
}
shuffleQuestionsInNewForm = function() {
var i,L,thisID,thisItem,thisQuestion,questionType;
L = arrayOfIDs.length;
for (i=0;i<L;i++) {
thisID = arrayOfIDs[i];
Logger.log('thisID: ' + thisID)
thisItem = newForm.getItemById(thisID);
newForm.moveItem(thisItem, i)
}
}
fncGetQuestionID();//Get all the question ID's and put them into an array
shuffle();
shuffleQuestionsInNewForm();
}

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.