I have automatic email alerts that go into a label in my inbox (through the reply-to) and are also sent to users (through the to: part of the email).
I'm looking to add onto my script that pulls information in the body of the email. Ultimately, I want to pull the recipient of the email (in the to: part) and put that in Column B of a google sheet. Any insight will be greatly appreciated.
Script:
// Modified from http://pipetree.com/qmacro/blog/2011/10/automated-email-to-task-mechanism-with-google-apps-script/
// Globals, constants
var LABEL_PENDING = "Example label/PENDING";
var LABEL_DONE = "Example label/DONE";
// processPending(sheet)
// Process any pending emails and then move them to done
function processPending_(sheet) {
// Date format
var d = new Date();
var date = d.toLocaleDateString();
// Get out labels by name
var label_pending = GmailApp.getUserLabelByName(LABEL_PENDING);
var label_done = GmailApp.getUserLabelByName(LABEL_DONE);
// The threads currently assigned to the 'pending' label
var threads = label_pending.getThreads();
// Process each one in turn, assuming there's only a single
// message in each thread
for (var t in threads) {
var thread = threads[t];
// Gets the message body
var message = thread.getMessages()[0].getBody();
// Processes the messages here
orderinfo = message.split("example split");
rowdata = orderinfo[1].split(" ");
// Add message to sheet
sheet.appendRow([rowdata[1]]);
// Set to 'done' by exchanging labels
thread.removeLabel(label_pending);
thread.addLabel(label_done);
}
}
// main()
// Starter function; to be scheduled regularly
function main_emailDataToSpreadsheet() {
// Get the active spreadsheet and make sure the first
// sheet is the active one
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.setActiveSheet(ss.getSheets()[0]);
// Process the pending emails
processPending_(sh);
}
You can access the recipient data with the getTo() function of the message. You could simply add a line that saves itin the column
//Gets the message body and recipent
var message = thread.getMessages()[0].getBody();
var recipient = thread.getMessages()[0].getTo();
//...
// Add message and recipient to sheet
sheet.appendRow([rowdata[1], recipient]);
More info on the function of the gmailMessage class -> https://developers.google.com/apps-script/reference/gmail/gmail-message
Related
Is there a way to make the .getEventById or .getEventSereiesById return anyhting other than null? I get valid ID for the initial event creation and can make that into a full functional URL but cannot use it in its native environment for its native purpose.
I am trying to make a basic google sheets schedule system that can refer to the calendar invite to check for changes and update the sheet or vise versa based on which side is further out in time. The system will be used in an environment where the scheduling has multiple users and meetings can be moved around a lot, generally further out in time. Everything works right up until i try to get information from the calendar even, .getStartTime(), due to the .getEvent calls returning null. not sure how to fix what other sources are telling me is a nonfunctional command that yet still "functions as intended".
function IEPscheduler() {
var spreadsheet = SpreadsheetApp.getActiveSheet(); // call sheet
//var calendarID = spreadsheet.getRange("H1").getValue();
var eventCal = CalendarApp.getCalendarById("mascharterschool.com_0edapns33khde9ig0di31i2mvc#group.calendar.google.com");
var signups = spreadsheet.getRange("A2:C2").getValues();
var lr = spreadsheet.getLastRow();
var lc = spreadsheet.getLastColumn(); //
var count = spreadsheet.getRange(2,1,lr-1,lc-1).getValues();// get meeting data
for (x=0; x<count.length; x++){
var shift = count[x]; // pull row from meeting data
var Start = shift[0];
var End = shift[1];
var Student = shift[2];
var guests = shift[3];
var description = shift[4];
var location = shift[5];
var run=shift[6]; // run following based on status column
// new meeting is scheduled
if(run == null || run == ''){
var event = {
'location': location,
'description':description ,
'guests':guests +',',
'sendInvites': 'True',
}
var invite = eventCal.createEvent(Student, Start, End, event);
invite.setGuestsCanInviteOthers(true); // allow guests to invite others
var eventId = invite.getId();
var date = invite.getDateCreated();
spreadsheet.getRange(x+2,7).setValue('Invite created'); // set status in sheet
spreadsheet.getRange(x+2,8).setValue(date); // inital date for created meeting invite
spreadsheet.getRange(x+2,9).setValue(eventId);
}
// check existing meetings for updates
else {
var id = shift[9];
var invite = eventCal.getEventSeriesById('id');
// if the time or location has changed update calander
if(invite.getStartTime() !== Start || invite.getEndTime() !== End || invite.getLocation() !== location){
// if sheet override flagged
if(shift[lc-1] !== null || Shift[lc-1] !== ''){
invite.setTime(Start,End); // update start/end time
invite.setLocation(location); // update location
}
// if canalder invite is further out than spreadsheet --> update spreadsheet
if(invite.getStartTime() >> Start){
spreadsheet.getRange(x+2,1).setValue();
spreadsheet.getRange(x+2,2).setValue();
}
// if spread sheet time is later than invite --> updater invite
else{
invite.setTime(Start,End); // update start/end time
invite.setLocation(location); // update location
}
var date = invite.getLastUpdate();
spreadsheet.getRange(x+2,7).setValue('Updated'); // set new status in sheet
spreadsheet.getRange(x+2,8).setValue(date); // set date meeting was updated
}
// if guest list has changed ???
if
}
}
}
// set script to be runnable from sheet tool bar
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Sync to Calendar') // tool bar banner
.addItem('Create Events Now', 'IEPscheduler') // sub catageory (title, function to run)
.addToUi();
}
We actually figured it out shortly after posting and I couldn't get back to this. Turns out the ID from .getId is the iCalUID and the .getEventById() takes a iCalID. The difference is that the UID has '#google.com' appended to the end of the ID. Split at the '#' and the get event works perfectly.
It's a stupid quirk that the getId command returns the right data in a useless form that requires editing to be used for its intended purpose.
No nulls returned for me with this script:
function getEvents() {
const cal=CalendarApp.getDefaultCalendar();
const dt=new Date();
const start=new Date(dt.getFullYear(),dt.getMonth()-1,dt.getDate());
const end=new Date(dt.getFullYear(),dt.getMonth(),dt.getDate());
var events=cal.getEvents(start, end);
let eObj={idA:[],tA:[]}
events.forEach(function(ev,i){
eObj.idA.push(ev.getId());
eObj.tA.push(cal.getEventById(ev.getId()).getTitle());
});
Logger.log(JSON.stringify(eObj));
return eObj;
}
I am working on a Google Form that allows our employees to submit an in-field inspection of their equipment. I have a script that takes the form responses and creates a new sheet based on the date and the specific unit number of the equipment. The user goes through a checklist and selects either "Good" or "Needs Repair" for each item on the list. They can also add comments and upload pictures of any issues.
I am trying to have the script automatically send an email if "Needs Repair" is selected for any of the checks, as well as if the user adds a comment or a picture. This way we do not have to open every submitted sheet to know if any repairs are required. What I have is just not sending emails and I cannot figure out why. Any help is greatly appreciated!
Here is my current script:
function onFormSubmit() {
// onFormSubmit
// get submitted data and set variables
var ss = SpreadsheetApp.openById("*Spreadsheet Link*");
var sheet = ss.getSheetByName("Submissions");
var row = sheet.getLastRow();
var Col = sheet.getLastColumn();
var headings = sheet.getRange(1,1,1,Col).getValues();
var lastRow = sheet.getRange(row, 1, 1, Col);
var UnitNumber = sheet.getRange(row,3).getValue();
var newSheet = sheet.getRange(row,4,Col).getValue();
var fileExist = false;
var drillSheet = null;
var folder = DriveApp.getFoldersByName("Fraser Drill Inspections").next();
var files = folder.getFilesByName(UnitNumber);
var file = null;
var employee = sheet.getRange(row,2);
var checks = sheet.getRange(row, Col, 1, 20);
// check if Drill has sheet
while (files.hasNext())
{
fileExist = true;
file = files.next();
break;
}
if (fileExist) //If spreadsheet exists, insert new sheet
{
drillSheet = SpreadsheetApp.openById(file.getId());
drillSheet.insertSheet("" + newSheet);
}
else //create new spreadsheet if one doesn't exist
{
drillSheet = SpreadsheetApp.create(UnitNumber);
var ssID = drillSheet.getId();
file = DriveApp.getFileById(ssID);
file = file.makeCopy(UnitNumber, folder);
DriveApp.getFileById(ssID).setTrashed(true);
drillSheet = SpreadsheetApp.openById(file.getId());
drillSheet.renameActiveSheet(newSheet);
}
// copy submitted data to Drill sheet
drillSheet.getSheetByName(newSheet).getRange(1,1,1,Col).setValues(headings);
drillSheet.appendRow(lastRow.getValues()[0]);
drillSheet.appendRow(['=CONCATENATE(B6," ",B5)']);
drillSheet.appendRow(['=TRANSPOSE(B1:2)']);
//Hide top rows with raw data
var hiderange = drillSheet.getRange("A1:A3");
drillSheet.hideRow(hiderange);
//Widen columns
drillSheet.setColumnWidth(1,390);
drillSheet.setColumnWidth(2,700);
//Send email if there are any comments or if anything needs repair
if(lastRow.getValues() == "Needs Repair") {
function SendEmail() {
var ui = SpreadsheetApp.getUi();
MailApp.sendEmail("email#domain.com", "Drill Needs Repair", "This drill requires attention according to the most recent inspection report.")
}
}
}
The function to send an email is:
GmailApp.sendEmail(email, subject, body);
Try changing
if(lastRow.getValues() == "Needs Repair") {
function SendEmail() {
var ui = SpreadsheetApp.getUi();
MailApp.sendEmail("email#domain.com", "Drill Needs Repair", "This drill requires attention according to the most recent inspection report.")
}
}
to just the following:
if(lastRow.getValues() == "Needs Repair") {
GmailApp.sendEmail("youremail#domain.com", "Drill Needs Repair", "This drill requires attention according to the most recent inspection report.");
}
It looks like you've still got some additional work to do too, e.g. to make it send to the email address from the form submission instead of a hardcoded one.
the following script below will read my email and pull a value from an email as well as the recipient of the message. I'm looking to add to the code in which I just get the email address for the recipient.
Currently, the code will process: John Doe *** john.doe#gmail.com ****
- I just want the code to pull john.doe#gmail.com, without the arrow bracket symbols
Any insight on where to add this is greatly appreciated!
// Modified from http://pipetree.com/qmacro/blog/2011/10/automated-
email-to-task-mechanism-with-google-apps-script/
// Globals, constants
var LABEL_PENDING = "example label/PENDING";
var LABEL_DONE = "example label/DONE";
// processPending(sheet)
// Process any pending emails and then move them to done
function processPending_(sheet) {
// Date format
var d = new Date();
var date = d.toLocaleDateString();
// Get out labels by name
var label_pending = GmailApp.getUserLabelByName(LABEL_PENDING);
var label_done = GmailApp.getUserLabelByName(LABEL_DONE);
// The threads currently assigned to the 'pending' label
var threads = label_pending.getThreads();
// Process each one in turn, assuming there's only a single
// message in each thread
for (var t in threads) {
var thread = threads[t];
// Gets the message body
var message = thread.getMessages()[0].getBody();
var recipient = thread.getMessages()[0].getTo();
// Processes the messages here
orderinfo = message.split("example");
rowdata = orderinfo[1].split(" ");
// Add message to sheet
sheet.appendRow([rowdata[1], recipient]);
// Set to 'done' by exchanging labels
thread.removeLabel(label_pending);
thread.addLabel(label_done);
}
}
// main()
// Starter function; to be scheduled regularly
function main_emailDataToSpreadsheet() {
// Get the active spreadsheet and make sure the first
// sheet is the active one
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.setActiveSheet(ss.getSheets()[0]);
// Process the pending emails
processPending_(sh);
}
Regarding your last error message:
var LABEL_PENDING = "example label/PENDING";
var LABEL_DONE = "example label/DONE";
script will search labels with the name: "example label/PENDING" and "example label/DONE". Are you sure that you have the label with name "example label/PENDING" or "example label/DONE"?
Here is a little bit modified code based on your example. You just need to create label "PENDING" and mark some messages with this label.
var LABEL_PENDING = "PENDING";
function processPending () {
var sheet = SpreadsheetApp.getActive().getActiveSheet();
// Date format
var d = new Date();
var date = d.toLocaleDateString();
// Get out labels by name
var label_pending = GmailApp.getUserLabelByName(LABEL_PENDING);
// The threads currently assigned to the 'pending' label
var threads = label_pending.getThreads();
// Process each one in turn, assuming there's only a single
// message in each thread
for (var i = 0; i <threads.length; i++) {
var thread = threads[i];
// Gets the recipient
var recipient = thread.getMessages()[0].getTo();
// Add recipient to sheet
sheet.appendRow([recipient]);
}
}
I'm new to scripting so I hope someone can help me create one.
I'm trying to create a script for a sheet that can send an email when a custom menu is pressed.
Here's a file to work on.
https://docs.google.com/spreadsheets/d/1Ea-3eZoclHrAkZLwRmWWFbmbnn4dESNWvK_6pn1DCbE/edit?usp=sharing
Also, it should only send it if a column (ex. Column I) has a specific Value like 'Approved'
Email content should look like:
Subject: Leave Application # 'ColumnC'
Hi 'ColumnA',
We received your 'ColumnB' request for 'ColumnE'
Status: 'ColumnG'
More Details: 'ColumnH'
-Admin
Email should be sent to Column E and F.
The script must also update the spreadsheet to avoid duplicate emails.
Here is the working example
Here is the code:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var startRow = 2; // First row of data to process
var lastRow = sheet.getSheetByName('Journal').getLastRow(); // Last row with content
var rangeEmailSent = sheet.getRangeByName('Journal!EmailSent');
var dataEmailSent = rangeEmailSent.getValues();
var dataRequestedBy = sheet.getRangeByName('Journal!RequestedBy').getValues();
var dataRequestType = sheet.getRangeByName('Journal!RequestType').getValues();
var dataRefNo = sheet.getRangeByName('Journal!RefNo') .getValues();
var dataStatus = sheet.getRangeByName('Journal!Status') .getValues();
var dataToEmail = sheet.getRangeByName('Journal!ToEmail') .getValues();
var dataSupComment = sheet.getRangeByName('Journal!SupervisorComment').getValues();
var subjectTemplate = sheet.getRangeByName('SubjectTemplate1').getValue();
var bodyTemplate = sheet.getRangeByName('BodyTemplate1').getValue();
var msgSubject;
var msgBody;
for (var i = (startRow-1); i <= (lastRow-1); i++) {
// send e-mail if "Email Sent" is not blank and if "Status" is not empty
if ( !(dataEmailSent[i]=='Yes') && !(dataStatus[i] =='')) {
msgSubject = subjectTemplate.replace('$REF$', dataRefNo[i]);
msgBody = bodyTemplate
.replace('$REQUESTED_BY$', dataRequestedBy[i])
.replace('$REQUEST_TYPE$', dataRequestType[i])
.replace('$EMAIL$', dataToEmail[i])
.replace('$STATUS$', dataStatus[i])
.replace('$SupervisorComment$', dataSupComment[i]);
// Logger.log(msgSubject);
// Logger.log(msgBody);
MailApp.sendEmail(dataToEmail[i], msgSubject, msgBody);
// Change "Email sent" to "Yes"
rangeEmailSent.getCell(i+1,1).setValue('Yes'); // note: getCell(1,1) refers to the 1st cell
}
}
}
I used a Google Forms tutorial to tweak Form data to merge into a PDF and then send to an email. I am getting the following error message when I try to run the script:
TypeError: Cannot read property "values" from undefined. (line 11, file "Code")
I do not know how to fix the problem. I have searched the web for an answer. Here is a copy of the script. I marked the 2 lines where the script is giving an error:
var docTemplate = "1ZSqmId2BBjtz6PmgQEmusjnkHGsFKD1CBSq0rrQk6Kc";
var docName = "TestCertificate";
// When Form Gets submitted
function onFormSubmit(e) {
//Get information from form and set our variables
var email_address = "EMAIL#example.com";
//**(THIS IS WHERE THE ERROR IS OCCURRING ON THESE 2 LINES BELOW!)**
var full_name = e.values[2];
var Activity = e.values[3];
// Get document template, copy it as a new temp doc, and save the Doc’s id
var copyId = DocsList.getFileById(docTemplate)
.makeCopy(docName+' for '+full_name)
.getId();
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the document’s body section
var copyBody = copyDoc.getActiveSection();
// Replace place holder keys,in our google doc template
copyBody.replaceText('keyFullName', full_name);
copyBody.replaceText('keyActivity', Activity);
// Save and close the temporary document
copyDoc.saveAndClose();
// Convert document to PDF
var pdf = DocsList.getFileById(copyId).getAs("application/pdf");
// Attach PDF and send the email
var subject = "Report";
var body = "Here is the form for " + full_name + "";
MailApp.sendEmail(email_address, subject, body, {htmlBody: body, attachments: pdf});
// Delete temp file
DocsList.getFileById(copyId).setTrashed(true);
}
Here are links to the form and certificate I was testing.
Form/Spreadsheet
Document Template
The error you're seeing is because you're running a trigger function in the Script Editor. When you do this, the Event Parameter e is not defined - that's what the error message is saying.
For more background, see How can I test a trigger function in GAS?
Here's a test function that will run your onFormSubmit() function multiple times, with the data that's already in your spreadsheet. It reads each row of the sheet, generates an object to simulate the Event you would get when a form was submitted, then calls the trigger function. If you place breakpoints inside onFormSubmit(), or rely on Logger.log(), this technique will allow you to test your trigger function.
function test_onFormSubmit() {
var dataRange = SpreadsheetApp.getActiveSheet().getDataRange()
var data = dataRange.getValues();
var headers = data[0];
// Start at row 1, skipping headers in row 0
for (var row=1; row < data.length; row++) {
var e = {};
e.values = data[row];
e.range = dataRange.offset(row,0,1,data[0].length);
e.namedValues = {};
// Loop through headers to create namedValues object
for (var col=0; col<headers.length; col++) {
e.namedValues[headers[col]] = e.values[col];
}
// Pass the simulated event to onFormSubmit
onFormSubmit(e);
}
}
I've done no other debugging of your original function... but this gets rid of that error message, so you can continue testing.
I use the below code to test my triggers
//
//
function onFormSumbit(e) {
//Timestamp 1 Status Remarks 3 Expected Completion Date 4 TRB Number
var resp = e.source.getActiveSheet().getRange(e.range.rowStart,1, e.range.rowStart,5 ).getValues();
/*
function test(){
var ss=SpreadsheetApp.getActive();
var respsht=ss.getSheetByName("Form responses 1");
var resp = respsht.getRange("A119:P119").getValues();
*/
I will comment out the onformsubmit portion and run the test portion.
Once the function is working, I will comment out the test function and activate the onformsubmit function.
Simple solution :)