Gmail apps script reading mailer-daemon messages - google-apps-script

I would like to scan all my emails in Gmail, and extract only the mailer-daemon messages (to identify rejected email addresses).
When I'm using these methods, None of the mailer-daemon messages are returned - only the "valid" messages:
var ss = SpreadsheetApp.openById("1e29xgV1UU63SJEwF2aWQpWpcXMxyiylwEMGbuvbwADw");
var sheet = ss.getSheetByName("Email Addresses");
var row = 1;
sheet.getRange(row,1).setValue("Email Addresses");
row++;
var threads = GmailApp.getInboxThreads();
for (var i = 0; i < threads.length; i++) {
var messages = GmailApp.getMessagesForThread(threads[i]);
for (var j = 0 ; j < messages.length; j++) {
var txtBody = messages[i].getPlainBody();
var txtSender = messages[i].getFrom();
sheet.getRange(row,1).setValue(txtBody);
sheet.getRange(row,2).setValue(txtSender);
row++;
}
}
What can I use to process the mailer-daemon messages from the Mail Delivery Subsystem?
Thanks!

You should match the FROM: field of the message, something like:
var txtSender = messages[i].getFrom();
if (txtSender.indexOf("mailer-daemon") !== -1) {
// Log the entry in the spreadsheet
}

You should be filtering threads from the query itself, its more optimal (also paged).
function getBounced() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("Bounced Addresses");
var row = 1;
var regExp = /[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,}/i // "i" is for case insensitive
var threads = GmailApp.search('from:"mailer-daemon" subject:(failure|undeliverable)', 0, 50);
for (var i = 0; i < threads.length; i++) {
var messages = GmailApp.getMessagesForThread(threads[i]);
for (var j = 0 ; j < messages.length; j++) {
var txtSubject = messages[j].getSubject();
var txtBody = messages[j].getBody();
var bouncedEmail = regExp.exec(txtBody)[0];
sheet.getRange(row,1).setValue(bouncedEmail);
sheet.getRange(row,2).setValue(txtSubject);
row++;
}
}
}
I also added a little code to extract the bounced/rejected email with a RegExp

Related

Data is not written to Google Spreadsheet

My script copies "unread" incoming messages from mail from the marked folder to the google table, and then marks it as read. But sometimes there are failures: the script is executed, marks the letters "as read", but does not write to the table. That is, in fact, it turns out in the logger there is a record with all the contents of these letters, but they are not written to the table. In theory, you need to check whether the data was written to the table and only then mark the letters "as read". Maybe there is an error in the code that periodically makes itself felt? Guys, help me, I'm just learning.
function GmailmarkReadEnd() {
//this is just the stuff that recognizes what spreadsheet you're in
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var sheet = ss.getSheetByName('Лист2'); //gets the right sheet
/* searches your GMail for emails matching things "label:unread" + " label:support"
*/
var query = "label:unread" + " label:support";
var threads = GmailApp.search(query);
var supportStats = [];
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
for (var m = 0; m < messages.length; m++) {
var from = messages[m].getFrom(); //from field
var to = messages[m].getTo(); //to field
var time = messages[m].getDate(); //date field
var subject = messages[m].getSubject(); //subject field
var body = messages[m].getPlainBody(); //body field
var mId = messages[m].getId(); //id field to create the link later
if (query === "label:unread" + " label:support") {
supportStats.push([from,to,time,subject,body,'https://mail.google.com/mail/u/0/#inbox/'+mId]);
Logger.log(supportStats) // The log about which he spoke.
}
}
}
if(!threads.length) return; // if there are no unread ones, do nothing.
sheet.getRange(SpreadsheetApp.getActiveSheet().getLastRow()+1,2,supportStats.
length,supportStats[0].length).setValues(supportStats); //writes to the spreadsheet
GmailApp.markThreadsRead(threads); // marks as read
// ***Sorting Recorded Data by Date***
sheet.getRange('D:D').activate();
sheet.sort(4, false);
}
function GmailmarkReadEnd() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('Лист2'); //gets the right sheet
const query = "label:unread" + " label:support";
var threads = GmailApp.search(query);
var supportStats = [];
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
for (var m = 0; m < messages.length; m++) {
var from = messages[m].getFrom(); //from field
var to = messages[m].getTo(); //to field
var time = messages[m].getDate(); //date field
var subject = messages[m].getSubject(); //subject field
var body = messages[m].getPlainBody(); //body field
var mId = messages[m].getId(); //id field to create the link later
supportStats.push([from,to,time,subject,body,'https://mail.google.com/mail/u/0/#inbox/'+mId]);
Logger.log(supportStats) // The log about which he spoke.
}
}
if(!threads.length) return; // if there are no unread ones, do nothing.
sheet.getRange(SpreadsheetApp.getActiveSheet().getLastRow()+1,2,supportStats.length,supportStats[0].length).setValues(supportStats); //writes to the spreadsheet
GmailApp.markThreadsRead(threads); // marks as read
sheet.sort(4,false);
}
Thanks to everyone who helped. If anything, read the comments.
function GmailmarkReadEnd() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('Лист2'); //gets the right sheet
const query = "label:unread" + " label:support";
var threads = GmailApp.search(query);
var supportStats = [];
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
for (var m = 0; m < messages.length; m++) {
var from = messages[m].getFrom(); //from field
var to = messages[m].getTo(); //to field
var time = messages[m].getDate(); //date field
var subject = messages[m].getSubject(); //subject field
var body = messages[m].getPlainBody(); //body field
var mId = messages[m].getId(); //id field to create the link later
supportStats.push([from,to,time,subject,body,'https://mail.google.com/mail/u/0/#inbox/'+mId]);
Logger.log(supportStats) // The log about which he spoke.
}
}
if(!threads.length) return; // if there are no unread ones, do nothing.
sheet.getRange(sheet.getLastRow()+1,2,supportStats.length,supportStats[0].length).setValues(supportStats); //writes to the spreadsheet
GmailApp.markThreadsRead(threads); // marks as read
sheet.sort(4, false);
}

Google Apps Script Why it only searches for one (first) attachment

I have two codes, the first of which works and shows all attachments and the second shows only the first. "getAttachmentAndMessage" is used by several of my scripts so I need to have it in a separate function in order not to duplicate my configuration. Please help.
//this function get me all attachments
//this function is just an example of how I built my code below;
function searchEmailsData(){
var search = GmailApp.search('in:inbox newer_than:3d');
var threads = GmailApp.getMessagesForThreads(search);
for (var i = 0 ; i < threads.length; i++) {
var thread = threads[i];
for (var j = 0; j < thread.length; j++) {
var message = thread[j];
var attachments = message.getAttachments();
for (var k = 0; k < attachments.length; k++) {
var attachment = attachments[k];
Logger.log(attachment.getName());
}
}
}
}
//this functions get me only first attachment but I need all of them;
function searchEmailsData2(){
var search = GmailApp.search('in:inbox newer_than:3d');
var threads = GmailApp.getMessagesForThreads(search);
for (var i = 0 ; i < threads.length; i++) {
var thread = threads[i];
var obj = getAttachmentAndMessage(thread);
Logger.log(obj[1].getName())
}
}
function getAttachmentAndMessage(thread){
for (var j = 0; j < thread.length; j++) {
var message = thread[j];
var attachments = message.getAttachments();
for (var k = 0; k < attachments.length; k++) {
var attachment = attachments[k];
var obj = [message, attachment];
return obj;
}
}
}
In order to return not the first attachment but rather all of them, you can modify the getAttachmentAndMessage() function as follows:
function getAttachmentAndMessage(thread) {
var results = [];
for (var j = 0; j < thread.length; j++) {
var message = thread[j];
var attachments = message.getAttachments();
var obj = {'message': message, 'attachments': attachments};
results.push(obj);
}
return results;
}
The above will return a list of objects, in which each objects contains a property message, and a property attachments (which is a list of attachments).
In order to return a list containing only the attachments in the thread, you can use the following variation of the code above:
function getAttachmentAndMessage(thread) {
var results = [];
for (var j = 0; j < thread.length; j++) {
var message = thread[j];
var attachments = message.getAttachments();
results = results.concat(attachments);
}
return results;
}
Your original code
In your original getAttachmentAndMessage() code, you were using a return statement inside of the for loop. That means that upon finding the first message (first iteration of the outer loop) and upon finding its first attachment (first iteration of the inner loop) the function would simply return one value, which is a list containing the first message and its first attachment.

Google-script GmailApp search for label or nouserlabels

I'm trying to create a script that will allow me to search for e-mails and their attachments by label name or no user labels. If in searchForLabels is more than one entry, the script does not work.
function searchLabels(){
//if there is more than one entry here, the script does not work
var searchForLabels =
[
'has:nouserlabels',
'label:Test1'
];
for (var l = 0; l < searchForLabels.length; l++) {
var threads = GmailApp.search('in:inbox newer_than:4d' + searchForLabels);
var msgs = GmailApp.getMessagesForThreads(threads);
Logger.log(searchForLabels)
if (searchForLabels == 'has:nouserlabels'){
for (var i = 0 ; i < msgs.length; i++) {
for (var j = 0; j < msgs[i].length; j++) {
var message = msgs[i][j];
var from = message.getFrom();
var subject = message.getSubject();
var getAttachments = message.getAttachments();
var body = message.getPlainBody();
var getTo = message.getTo();
Logger.log(subject)
for (var k = 0; k < getAttachments.length; k++) {
var attachment = getAttachments[k];
var content = attachment.getContentType();
//rest of my code
}
}
}
}
}
}
I made two little changes over your code. After testing it, it works as you requested.
The first one is on the var threads = GmailApp.search('in:inbox newer_than:4d ' + searchForLabels[l]); line. I used the l iterator on the searchForLabels array. I used it because, reading the context of the line, it seems appropriate. This change will iterate over the tags. Forgive me if this was not your original intention.
The second change is required for the script to work. I commented out the if (searchForLabels == 'has:nouserlabels') {, because it will never be true if the searchForLabels array has more than one element. This is the error that you detected. Please, notice how the correspondent } is commented out too.
This is the final and working version of the script:
function searchLabels() {
//if there is more than one entry here, the script does not work
var searchForLabels = [
'has:nouserlabels',
'label:Test1'
];
for (var l = 0; l < searchForLabels.length; l++) {
var threads = GmailApp.search('in:inbox newer_than:4d ' + searchForLabels[l]);
var msgs = GmailApp.getMessagesForThreads(threads);
Logger.log(searchForLabels)
//if (searchForLabels == 'has:nouserlabels') {
for (var i = 0; i < msgs.length; i++) {
for (var j = 0; j < msgs[i].length; j++) {
var message = msgs[i][j];
var from = message.getFrom();
var subject = message.getSubject();
var getAttachments = message.getAttachments();
var body = message.getPlainBody();
var getTo = message.getTo();
Logger.log(subject)
for (var k = 0; k < getAttachments.length; k++) {
var attachment = getAttachments[k];
var content = attachment.getContentType();
//rest of my code
}
}
}
//}
}
}
I want to add that you can use the Gmail API on Apps Script to accomplish your request in a simple way. In particular, you can use Users.messages LIST to list all the mails with your selected tags. There you can see an example (click over JavaScript) where a function is ready to make a search. To enable this API you shall follow the guide for activating advanced services. Do not hesitate to ask for more clarifications or any question.
function searchLabels() {
var searchForLabels = [
'has:nouserlabels',
'label:Test1'
];
for (var l = 0; l < searchForLabels.length; l++) {
var threads = GmailApp.search('in:inbox newer_than:4d ' + searchForLabels[l]);
var msgs = GmailApp.getMessagesForThreads(threads);
Logger.log(searchForLabels)
if (searchForLabels[l] == 'has:nouserlabels') { //limits emails to those without tag
//if (searchForLabels[l] == 'label:Test1') { //or to those with tag
for (var i = 0; i < msgs.length; i++) {
for (var j = 0; j < msgs[i].length; j++) {
var message = msgs[i][j];
var from = message.getFrom();
var subject = message.getSubject();
var getAttachments = message.getAttachments();
var body = message.getPlainBody();
var getTo = message.getTo();
Logger.log(subject)
for (var k = 0; k < getAttachments.length; k++) {
var attachment = getAttachments[k];
var content = attachment.getContentType();
//rest of my code
}
}
}
}
}
}

Why doesn't this script collect all gmails?

I have a google app script that collects information about Gmail messages and then pastes it into a google sheet. Trouble is it doesn't get ALL of the messages. It only picks up the first one of each thread. I feel like I am missing something to loop through each thread? Any suggestions?
function getMail(){
var myspreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var mysheet = myspreadsheet.getSheetByName("Sheet3");
var start = 0;
var max = 99;
var count =0;
var row = mysheet.getLastRow()+1
var maxDate = mysheet.getRange("B1").getValue()
while(count < 4)
{
var threads = GmailApp.getInboxThreads(start , max);
var messages = GmailApp.getMessagesForThreads(threads);
var froms = [];
messages.get
for(var i = 0; i < threads.length; i++)
{
var msgDate = messages[i][0].getDate();
if(msgDate>maxDate){
froms.push([messages[i][0].getDate(),messages[i][0].getFrom(),messages[i][0].getSubject(),messages[i][0].getPlainBody()]);
}
}
if(froms.length>0){
mysheet.insertRows(2, froms.length)
mysheet.getRange(2,1,froms.length,4).setValues(froms);
}
start = start + 100;
count++;
}
}
Your current script is only grabbing messages[i][0], the first message in that group for the thread. Instead you need to loop through all of the messages using two for loops, as you can see in the script below I use messages[i][j].
function getMail() {
var mySpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var mySheet = mySpreadsheet.getSheetByName("Sheet3");
var start = 0;
var max = 99;
var count = 0;
var maxDate = mySheet.getRange("B1").getValue();
while(count < 4) {
var threads = GmailApp.getInboxThreads(start, max);
var messages = GmailApp.getMessagesForThreads(threads);
var froms = [];
for(var i = 0; i < messages.length; i++) {
for(var j = 0; j < messages[i].length; j++) {
var msgDate = messages[i][j].getDate();
if(msgDate > maxDate) {
froms.push([msgDate,messages[i][j].getFrom(),messages[i][j].getSubject(),messages[i][j].getPlainBody()]);
}
}
}
if(froms.length > 0) {
mySheet.insertRows(2, froms.length);
mySheet.getRange(2, 1, froms.length, 4).setValues(froms);
}
start = start + 100;
count++;
}
}
Notable changes:
removed var rows because it wasn't used anywhere in the script.
changed first for loop to run for messages.length rather than
threads.
added another for loop to loop through every message in
messages[i].
you were getting messages[i][0].getDate() twice, so I just used the variable already defined for adding to the array.
minor grammatical/spacing changes for consistency across script.

Google Spreadsheet setBackgroundColors() "Deprecated"

A gs I have been using in the past to check for duplicates, is no longer working. The script would check all cells in the spread sheet if any were identical it would highlight all their occurrences green. I also had another function that would revert all the cells back to white.
setBackgroundColors() has been deprecated; people have been recommended to now use setBackground(). The script still doesn't work...
Here is my gs, make a copy and fiddle with it. Many Thanks...
https://docs.google.com/spreadsheets/d/1UELTxZRZPKQKU9NsQwNefvdxJDM0xDt8904sZy3etoY/edit#gid=0
Here is the script.
/**
* Retrieves all the rows in the active spreadsheet that contain data and logs the
* values for each row.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function readRows() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
Logger.log(row);
}
};
/**
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the readRows() function specified above.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function onOpen() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Check Directory",
functionName : "CheckDirectory"
}];
spreadsheet.addMenu("Script Center Menu", entries);
};
function CheckDirectory() {
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getDataRange();
var data = dataRange.getValues();
var numRows = data.length;
var numColumns = data[0].length;
var formats = [];
var values = [];
for (var i = 0; i < numRows; i++) {
formats[i] = [];
for (var j = 0; j < numColumns; j++) {
formats[i][j] = 'white';
if (data[i][j] != '') {
values.push([data[i][j], i, j]);
}
}
}
var numValues = values.length;
for (var k = 0 ; k < numValues - 1; k++) {
if (formats[values[k][1]][values[k][2]] == 'white') {
for (var l = k + 1; l < numValues; l++) {
if (values[k][0] == values[l][0]) {
formats[values[k][1]][values[k][2]] = 'green';
formats[values[l][1]][values[l][2]] = 'green';
}
}
}
}
dataRange.setBackground(formats);
};
function resetCheckDirectory() {
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getDataRange();
var data = dataRange.getValues();
var numRows = data.length;
var numColumns = data[0].length;
var formats = [];
var values = [];
for (var i = 0; i < numRows; i++) {
formats[i] = [];
for (var j = 0; j < numColumns; j++) {
formats[i][j] = 'white';
if (data[i][j] != '') {
values.push([data[i][j], i, j]);
}
}
}
var numValues = values.length;
for (var k = 0 ; k < numValues - 1; k++) {
if (formats[values[k][1]][values[k][2]] == 'white') {
for (var l = k + 1; l < numValues; l++) {
if (values[k][0] == values[l][0]) {
formats[values[k][1]][values[k][2]] = 'white';
formats[values[l][1]][values[l][2]] = 'white';
}
}
}
}
dataRange.setBackground(formats);
};
Use setBackgrounds(). With an s since it's a method that applies multiple background colors to multiple cells