简体   繁体   中英

Sending email with script from Google spreadsheet - need loop

I have a spreadsheet that contains different events on different days.

Each event has an instructor and a facilitator.

The script is programmed to send a reminder to the instructor and the facilitator, the night before each event is scheduled.

The problem is there can be multiple events on each day with the same facilitator but different instructor.

The email is currently sending out one email per day - no matter how many days or facilitators.

I need it to send out one email per line and I am having trouble figuring out the necessary loop. I would appreciate help. Here is my script:

   function SGIDReminder() {
  //get the spreadsheet object
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  //set the first sheet as active
  SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[0]);
  //fetch this sheet
  var sheet = spreadsheet.getActiveSheet();

  //figure out what the last row is
  var lastRow = sheet.getLastRow();

  //the rows are indexed starting at 1; first row is header row so start with 2
  var startRow = 2;

  //grab column 13; it contains the reminder days left
  var range = sheet.getRange(2,13,lastRow-startRow+1, 1);
  var numRows = range.getNumRows();
  var reminder_send_values = range.getValues();

  //grab column for name of reminder
  range = sheet.getRange(2,4,lastRow-startRow+1, 1);
  var course_values = range.getValues();

  //grab column for location
  range = sheet.getRange(2,3,lastRow-startRow+1, 1);
  var location_values = range.getValues();

  //grab column for time
  range = sheet.getRange(2,2,lastRow-startRow+1, 1);
  var time_values = range.getValues();

  //grab column for email
  range = sheet.getRange(2,10,lastRow-startRow+1, 1);
  var email_values = range.getValues();

  //grab column for instructor email
  range = sheet.getRange(2,7,lastRow-startRow+1, 1);
  var instructor_email_values = range.getValues();

  var warning_count = 0;
  var msg = "";

  //Loop over the reminder_send values
  //changed time to hour to avoid message formatting and date addition javascript wanted to add
  for (var i = 0; i <= numRows - 1; i++) {
    var reminder_send = reminder_send_values[i][0];
    if(reminder_send == 1) {
      //if it is 1, do something with the data
      var course = course_values[i][0];
      var location = location_values[i][0];
      var hour = time_values[i][0];
      var email =  email_values[i][0];
      var instructor = instructor_email_values[i][0];
      msg = msg + "Reminder: You have an SGID scheduled tomorrow  at "+hour+" in "+location+" for "+course+".\n Please remind students to bring a smartphone or web capable device with them to class.";
      warning_count++;
    }
  }
  //cc instructor - but could bcc or add other emails, from cte, reply to Gregg
  if(warning_count) {
    MailApp.sendEmail(email, "SGID Reminder Message", msg,
                      {bcc: "myemail@miamioh.edu", cc: instructor, name: "CTE", replyTo: "coordinator@miamioh.edu"});
   }                      
};

This is not a turn-key solution, but illustrates what you could do.

In order to send more than one email, you need to collect emails for every case that requires an email. Generally, this is done using an Object or an Array , or possibly an Array of Object s (eg to bundle more than one piece of information).

Probably, it is worthwhile to send only a single email to each instructor containing a list of all the events they have, and a single email to each facilitator containing a list of all the events they have.

This example uses an Object to hold the instructor and facilitator information for email processing outside of the spreadsheet data loop. Each relevant email is used as an object key, with the value that is an array of event information.

const data = sheet.getDataRange().getValues();
const headers = data.shift();
const reminderColText = "Reminder Days Left", // Title of the header col
      compareCol = headers.indexOf(reminderColText),
      // If the row & column intersection has this value, an email is sent for the row's data
      sendIfDays = 1;
if (compareCol === -1)
  throw new Error("Did not find the header column titled '" + reminderColText + "'")

// Prune the sheet's data to only that which we care about.
const events = data.filter(function (row) { return row[compareCol] === sendIfDays; });

const infoIndices = { eventName: 0, // Event name in Col A
                      eventTime: 1,
                      eventLoc: 3, // Event location in Col D
                      instructorEmail: 4,
                      facilitatorEmail: 5 };
const emailInfo = { instructors: {}, facilitators: {} };
events.forEach(function (row) {
  var ins = row[infoIndices.instructorEmail],
      fac = row[infoIndices.facilitatorEmail],
      name = row[infoIndices.eventName],
      time = row[infoIndices.eventTime],
      loc = row[infoIndices.eventLoc];

  // Create an Array for each instructor / facilitator email
  if (!emailInfo.instructors[ins])
    emailInfo.instructors[ins] = [];
  if (!emailInfo.facilitators[fac])
    emailInfo.facilitators[fac] = [];

  // Add the event data to the relevant array
  var eData = { name: name, time: time, loc: loc };
  emailInfo.instructors[ins].push(eData);
  emailInfo.facilitators[fac].push(eData);
});

// Send emails based on the collected information.
[ {r: emailInfo.instructors,  f: getFormattedInstructorMessage_},
  {r: emailInfo.facilitators, f: getFormattedFacilitatorMessage_} 
].forEach( function (o) {
  var formatFunc = o.f;
  for (var email in o.r) {
    var recipientName = getNameFromEmailSomehow_(email);
    var msg = formatFunc(recipientName, o.r[email]);
    MailApp.sendEmail(email, "Subject", msg);
  }
});

The above assumes you have also written some background functions:

  • a function getNameFromEmailSomehow_ that converts an email to a name (eg an LDAP lookup, or maybe you have written the instructor/faciliator name in the row and include that in eData
  • two formatting functions getFormattedInstructorMessage_ and getFormattedFaciliatorMessage_ that take the recipient name and the list of all their events for that upcoming day, and consumes the list of objects to make the email text. You could return HTML (and use the other version of MailApp.sendEmail ) or just plain text, whichever you prefer.

An absolutely primitive example formatter:

function basicFormattedMessage_(to, events) {
  var msg = "Hello " + to + ",\n";
  msg += "You have " + events.length + " events tomorrow:\n";
  events.forEach(function (e) {
    msg += "\nName: " + e.name;
    msg += "\nTime: " + e.time;
    msg += "\nRoom: " + e.loc;
    msg += "\n";
  });
  return msg;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM