1

I want to send the email to the corresponding person with a attached table of that row based on the cell value. For example, In the sheet, when the the column D==="New" and "Ongoing", an email will send to the recipients of C column with a generated table of that row. I don't want onedit trigger as I will send the email only once in a week. When table will generate, it will only take column Resource, status, Due date and Link. I have write the code for sending email and as well creating a table. The problem is when I am creating the table, It is taking all the data where status is New. For this reason, all the recipients get the same table but I want the table in a way that the recipient will get only his corresponding row's table. I have attached my code here. Can anyone one suggest what should I add here? Sheet link: https://docs.google.com/spreadsheets/d/1GC59976VwB2qC-LEO2sH3o2xJaMeXfXLKdfOjRAQoiI/edit#gid=0

Code:

function myFunction() {
  var ss=SpreadsheetApp.getActiveSpreadsheet()
  var sheet=ss.getSheetByName("Sheet3")
  var sheetData=sheet.getRange(2,1,sheet.getLastRow()-1,sheet.getLastColumn()).getValues()
  var filteredRows_new = sheetData.filter(function(row){
    if (row[3] === 'New') {
      return row
    }
  })
  // create the html table
  var header=sheet.getRange(1,1,1,sheet.getLastColumn()).getValues()
  var resource=header[0][1]
  var status_r=header[0][3]
  var due_date_r=header[0][5]
  var link_r=header[0][10]
 var data=filteredRows_new.map(col=>[col[1],col[3],col[5],col[10]])
 var htmltemplate=HtmlService.createTemplateFromFile("email")
 htmltemplate.resource=resource
 htmltemplate.status_r=status_r
 htmltemplate.due_date_r=due_date_r
 htmltemplate.link_r=link_r
 htmltemplate.data=data
 var htmlformail=htmltemplate.evaluate().getContent()
 console.log(htmlformail)

  // extract only the new status data for email
  filteredRows_new.forEach(function(row) {
  //Email address
  var email = row[2];
  GmailApp.sendEmail(email,"automation","open the link for html", { htmlBody: htmlformail })
})

  //extract the rows for ongoing
  var filteredRows_ongoing = sheetData.filter(function(col){
    if (col[3] === 'ongoing') {
      return col
    }
  })
  //console.log(filteredRows_ongoing)
}

1 Answers1

0

I faced a very similar problem and it seems that there is no dedicated function in app script documentation for that. That why I tried to create a lib to be able to do it in an elegant manner.

Your file is lock, we cannot acces ! See bellow the best answer I can provide, some value like header name have to be updated with your data.

To be able to use those lib, you have to create two new gs script and a copy paste the two scripts UtilsGSheetTableHelper.gs and UtilsGmailHelper availlable there : https://github.com/SolannP/UtilsAppSsript

And then on the code.gs file

function macro(){
  // get range of cell with data from A1 to any cell near having value (call data region)
  var table = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet3").getRange("A1").getDataRegion();
  // create custom table filtered by the column having header "State" where the value match "New"
  var filterTable = new TableWithHeaderHelper(table) 
                .getTableWhereColumn("State").matchValueRegex(/(New)|(Ongoing)/);
  // for each row matching the criteria
  for(var i=0; i< filterTable.length() ; i++){
    // Get cell range value at column Mail
    var mail = filterTable.getWithinColumn("Mail").cellAtRow(i).getValue();
    // Any other value of column Target Value
    var anyOtherValue = filterTable.getWithinColumn("Target Value").cellAtRow(i).getValue();
    // Send email 
    MailApp.sendEmail({
      to:mail ,
      subject: "BIKINI ASSEMBLY",
      cc:cc,
      htmlBody:`<h1>Sheet table weekly</h1><hr><p>${anyOtherValue}<p>`,
    });
  } 
}

Then you can attach the script to a button to click at the end of the week.

As further improvement you can update a cell with the date of last mail send and even more !

Take care !

UPDATE

see the code for matching your request :

function macro(){
  // get range of cell with data from A1 to any cell near having value (call data region)
  var table = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet3").getRange("A1").getDataRegion();
  // create custom table filtered by the column having header "State" where the value match "New"
  var filterTable = new TableWithHeaderHelper(table) 
                .getTableWhereColumn("Status").matchValueRegex(/(New)/);
  // for each row matching the criteria
  for(var i=0; i< filterTable.length() ; i++){
    // Get cell range value at column Mail
    var mail = filterTable.getWithinColumn("Email").cellAtRow(i).getValue();
    // Any other value of column Target Value
    var bodyMail = filterTable.getWithinColumn("Description").cellAtRow(i).getValue();
    var subjectMail = filterTable.getWithinColumn("Title").cellAtRow(i).getValue();
    
    // Send email 
    MailApp.sendEmail({
      to:mail ,
      subject: subjectMail,
      htmlBody:subjectMail,
    });
  } 
}
  • Hi, Thanks for your help but I couldn't understand why I need the helper library? I have given access to the file. Can you elaborate what's the use of the helping library and where I should change it? – Anushka Nahid Oct 11 '22 at 13:29
  • hi @AnushkaNahid, that just an helper : same functionality with less code and easier to read – Puygrenier Solann Oct 11 '22 at 13:44
  • see updated code for your case (in the answer) – Puygrenier Solann Oct 11 '22 at 13:45
  • Hi, I am extremely sorry for the late reply. Yes it's working in the expected way but I need to create the table in the body mail. For example, when the status is new, the table will be created with column Resource, Due date and Link. So whenever the status is new, the recipient will get the table only for that row as email. I am trying to modify it. Let's see. But if you know easier, please feel free to update as well – Anushka Nahid Oct 11 '22 at 16:38
  • And one more thing, It's not going till the end of the sheet. As in the for loop condition it is i – Anushka Nahid Oct 11 '22 at 17:04
  • Yep @AnushkaNahid, you can filter using rather `.matchRegex(/((New)|(Ongoing)/)` and then in the loop make `var rowStatus = filterTable.getWithinColumn("Status").cellAtRow(i).getValue()` and make `if(rowStatus === "New")//your stuff` – Puygrenier Solann Oct 11 '22 at 17:19
  • The match is case sensitiv, mining ONGOING a'd Ongoing are not the same, I think that why it seems to not to ru for all cell – Puygrenier Solann Oct 11 '22 at 17:23
  • By the way fill free to validate the answer if it's okay – Puygrenier Solann Oct 11 '22 at 17:25
  • Thanks a lot!! Actually I didn't see that I put 'New' in the wrong format. Now it's fine. Thanks a lot for helping me out – Anushka Nahid Oct 11 '22 at 17:48
  • 1
    BTW, how I can validate the answer? I am sorry I am so new in this platform that's why asking – Anushka Nahid Oct 11 '22 at 17:51
  • I'm glad that help ! No worries there is first time, just be sure to read the posts about how to ask question and reply there is an "Accept" button somewere on this page – Puygrenier Solann Oct 11 '22 at 17:55
  • @AnushkaNahid see https://meta.stackexchange.com/questions/147531/how-mark-my-question-as-answered-on-stack-overflow – Puygrenier Solann Oct 11 '22 at 19:01
  • Thanks a lot for the link. I have marked it as accepted. Thank you and take care! – Anushka Nahid Oct 11 '22 at 19:54
  • Hi Puygrenier, I am thinking to modify the the script as my need has been changed. I have modified the question and it's been in this link. Have you ever encountered this type of problem? https://stackoverflow.com/questions/74086086/send-single-email-containing-a-table-based-on-a-condition-to-the-recipients-when?noredirect=1#comment130813136_74086086 – Anushka Nahid Oct 16 '22 at 19:47
  • @AnushkaNahid, i will reply within minute – Puygrenier Solann Oct 16 '22 at 20:38