What I have:
A google form with checkbox options so the user can choose ALL that
apply (6 total options)
For each option, there is a specific email associated with each option (6 different emails)
What is occurring:
When a single option is chosen, the email goes out to the correct person
When multiple options are chosen, an email goes out only to the first option
The spreadsheet collects the data correctly, showing all the options chosen, but only one email actually goes out
What I need:
Multiple emails sent to the different specified addresses if their option is one of the selected ones
Current Script:
function sendFormByEmail(e)
{
console.log(JSON.stringify(e))
// Remember to replace XYZ with your own email address
var named_values = e.namedValues
var teachername = named_values["Teacher Name"];
var info = named_values["Your message/announcement"];
var time = named_values["Please include time frame"];
var photos = named_values["Include photos with this form if applicable; you can also create the graphic for social media and include below"];
var announce = e.values[3];
var address = [];
if(announce.match('School Intercom Announcement')){
var address = "mhhsmedia#yanceync.net";
var subject = "School Announcement Request";
}
if(announce.match('MHHS Website')){
var address = "heritagecougars#yanceync.net";
var subject = "Website posting request";
}
if(announce.match('MHHS Social Media')) {
var address = "socialmedia#yanceync.net";
var subject = "Social Media Request";
}
if(announce.match('Week in Pics')) {
var address = "ycspics#yanceync.net";
var subject= "Week in Pics Request";
}
if(announce.match('Remind text message')){
var address = "jstipton#yanceync.net";
var subject = "Remind message request";
}
if(announce.match('Phone call home')){
var address = "blackboardcall#yanceync.net";
var subject = "All-Call Request";
}
// The variable e holds all the form values in an array.
// Loop through the array and append values to the body. ;
var email = address
var message = "";
for(var field in e.namedValues)
message += field + ' :: '
+ e.namedValues[field].toString() + "\n\n";
MailApp.sendEmail(email, subject, message);
}
Things I have tried with no luck:
I attempted to join the addresses with:
var email = address.join(",")
This gave me a script failure that address.join was not a function
I tried including under each if statement:
var email = "jstipton#yanceync.net";
var subject = "All-Call Request";
MailApp.sendEmail(email, subject, message);
This resulted in still only one email being sent to the first option chosen, regardless of how many were chosen after it.
Thank you in advance for your willingness to assist me!
If you have included,under each if statement, theMailApp.sendEmail code and only 1 email is send, that's because your are entering in only one condition.
But why announce match only 1 condition ? I believe there is only one value announce='Week in Pics' (or equivalent) passed into the sendFormByEmail(e) function.
So be sure that announce have a value like "School Intercom Announcement MHHS Website "
Just for you information, there is a lot to say about your code :
The way value is affected into address field (several var address) is not so good. You used array, that's a perfect start, but to add data into an array, it's the push method :
// 🔴 what you use
var address = []; // address = [] an array
var address = "mhhsmedia#yanceync.net"; // address = "mhhsmedia#yanceync.net" a string
var address = "heritagecougars#yanceync.net"; // address = "heritagecougars#yanceync.net" a string
// 🟢 what work
var address = []; // address = [] an array
address.push("mhhsmedia#yanceync.net"); // address = ["mhhsmedia#yanceync.net"] an array of string
address.push("heritagecougars#yanceync.net"); // address = ["mhhsmedia#yanceync.net","heritagecougars#yanceync.net"] an array of string
// So your code can look like as bellow
// ...
var address = [];
if(announce.match('School Intercom Announcement')){
address.push("mhhsmedia#yanceync.net");
subject.push("School Announcement Request");
}
if(announce.match('MHHS Website')){
address.push("heritagecougars#yanceync.net");
subject.push("Website posting request");
}
// ...
for (var email in address){
var subjectToSend = subject.pop()
//...
}
As improvement, you can use switch switch statement, that is far more easier to read than several if.
Finally, match is for regex, if you never heard of such thing have a look, it's a life changer.
Related
I'm trying to get the Description of a Site but it's always null in WebsInfo! Can someone please help me understand this? I also tried using OpenWeb but that was messing up the URL that I passed in.
var site = new SPSite(currentWeb.Url);
string url = currentWeb.Url + #"/" + siteName;
var webObject = site.AllWebs;
foreach (var web in webObject.WebsInfo)
{
siteDescription = web.Description;
}
I guess there is a bug in the WebsInfo that has never been resolved!! I ended up using SPWebCollection.
//This will find the current URL and iterate through it's site Collection
var oSiteCollection = new SPSite(SPContext.Current.Web.Url);
//Gets all webs meaning sub webs and their webs.
var collWebsites = oSiteCollection.AllWebs;
foreach (SPWeb web in collWebsites)
{
if (web.ServerRelativeUrl.StartsWith(kpi.BusinessUnitUrl))
{
kpi.BusinessUnitDescription = web.Description;
kpi.SiteSpecificAreaDescription = web.Description;
var collLists = web.Lists;
IterateLists(collLists, false, ref kpi);
}
}
This question already has answers here:
How can I test a trigger function in GAS?
(4 answers)
Closed 4 months ago.
I am trying to use a form submit to automatically complete a google doc template I have created. But I keep getting the error TypeError: Cannot read property 'values' of undefined, I am a complete newbie, can someone help me please?
function autoFillGoogleDocFromForm(e) {
//e.values is an array of form values
var timestamp = e.values[0];
var EmailAddress = e.values[1];
var CallReportWriter = e.values[2];
var DateOfMeeting = e.values[3];
var NameOfTheCustomerProspect = e.values[4];
var ContactNameFromClient = e.values[5];
var TitleandContacts = e.values[6];
var PresentfromSesomo = e.values[7];
var MeetingObjectives = e.values[8];
var MeetingResult = e.values[9];
var Background = e.values[10];
var Opportunities = e.values[11];
var Followuprequired = e.values[12];
var Responsible = e.values[13];
var Targetdates = e.values[14];
//file is the template file, and you get it by ID
var file = DriveApp.getFileById('12zJTxLgy_Nmxk1FScyZ3vqHzYnKQ55ckdQ8RsYy-MdA');
//We can make a copy of the template, name it, and optionally tell it what folder to live in
//file.makeCopy will return a Google Drive file object
var folder = DriveApp.getFolderById('1SorfCjOGknFVt1ch39MJ7atBorLf_Sdr')
var copy = file.makeCopy(DateOfMeeting + ',' + NameOfTheCustomer/Prospect, CallReport);
//Once we've got the new file created, we need to open it as a document by using its ID
var doc = DocumentApp.openById(copy.getId());
//Since everything we need to change is in the body, we need to get that
var body = doc.getBody();
//Then we call all of our replaceText methods
body.replaceText('{{MeetingDate}}', DateOfMeeting);
body.replaceText('{{NameOfCustomer}}', NameOfTheCustomer/Prospect);
body.replaceText('{{ReportWriterName}}', CallReportWriter);
body.replaceText('{{ContactNameFromClient}}', ContactNameFromClient);
body.replaceText('{{TitleAndContact}}', TitleandContacts);
body.replaceText('{{PresentFromSesomo}}', PresentfromSesomo);
body.replaceText('{{MeetingObjectives}}', MeetingObjectives);
body.replaceText('{{MeetingResults}}', MeetingResult);
body.replaceText('{{Background}}', Background);
body.replaceText('{{Opportunities}}', Opportunities);
body.replaceText('{{FollowUpRequired}}', Followuprequired);
body.replaceText('{{Responsible}}', Responsible);
body.replaceText('{{TargetDate}}', Targetdates);
//Lastly we save and close the document to persist our changes
doc.saveAndClose();
}
Open the script editor of the sheet where the form response is landing
//
function onFormSubmit(e) {
var resp = e.source.getActiveSheet().getRange(e.range.rowStart,1, e.range.rowStart,14 ).getValues();
var timestamp = resp[0][0];
var EmailAddress = resp[0][1];
var CallReportWriter = resp[0][2];
var DateOfMeeting = resp[0][3];
// continue your code - I have not tested it
}
In script editor, you have to install the on-form-submit trigger
Then as soon as form response lands, your code will run and do whatever you want.
We are seriously blocked. We have followed the documentation below (among many others) to set up the pub/sub pipelines, create service accounts, assign permissions and use the right scopes and feed types for registrations.
https://developers.google.com/classroom/guides/push-notifications
So programmatically we are able to do the following in .net using the API :
We can Create Courses
We can create registrations for a given courseid
We create/update courseworks for the course that we have created a registration.
All good so far,
BUT, we don't receive notifications for that created/update course work.
some code for clarity :
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer("sa-something#precise-asset-259113.iam.gserviceaccount.com")
{
User = "impersonated user",
Scopes = new string[] { "https://www.googleapis.com/auth/classroom.coursework.students" ,
"https://www.googleapis.com/auth/classroom.courses",
"https://www.googleapis.com/auth/classroom.push-notifications" }}
.FromPrivateKey("My private key"));
//Authorize request
var result = credential.RequestAccessTokenAsync(CancellationToken.None).Result;
var service = new ClassroomService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
});
// We get courses
var courses = service.Courses.List().Execute();
// We get one course for registration
var course = courses.Courses.First();
// We create registration
var registration = service.Registrations.Create(new Google.Apis.Classroom.v1.Data.Registration()
{
Feed = new Google.Apis.Classroom.v1.Data.Feed()
{
FeedType = "COURSE_WORK_CHANGES",
CourseWorkChangesInfo = new Google.Apis.Classroom.v1.Data.CourseWorkChangesInfo()
{
CourseId = course.Id
},
},
CloudPubsubTopic = new Google.Apis.Classroom.v1.Data.CloudPubsubTopic()
{
TopicName = "projects/precise-asset-259113/topics/test"
},
});
//Successful response - We get a registrationID
var response = registration.Execute();
var courseWork = new CourseWork()
{
CourseId = course.Id,
Title = "Ver Test",
Description = "Calculus",
WorkType = "ASSIGNMENT",
MaxPoints = 20.0,
State = "PUBLISHED",
AlternateLink = "www.uni.com",
CreatorUserId = course.OwnerId,
CreationTime = DateTime.UtcNow,
DueTime = new TimeOfDay() { Hours = 5, Minutes = 10, Nanos = 10, Seconds = 10 },
DueDate = new Date() { Day = 3, Month = 12, Year = 2019 },
Assignment = new Assignment() { StudentWorkFolder = new DriveFolder() { AlternateLink = "Somewhere", Title = "My Calculus" } }
};
//Create course work for the course that we registered
var courseWorkResponse = service.Courses.CourseWork.Create(courseWork, course.Id).Execute();
SubscriberServiceApiClient subscriber = SubscriberServiceApiClient.Create();
SubscriptionName subscriptionName = new SubscriptionName("precise-asset-259113", "test");
PullResponse pullResponse = subscriber.Pull(
subscriptionName, returnImmediately: true, maxMessages: 20);
// Check for push notifications BUT ....NADA!!!
foreach (ReceivedMessage msg in pullResponse.ReceivedMessages)
{
string text = Encoding.UTF8.GetString(msg.Message.Data.ToArray());
Console.WriteLine($"Message {msg.Message.MessageId}: {text}");
}
Can you please assist?
Thanks
There are several things you need to change in order to ensure you get the notifications:
You need to create your subscription before you send the request that will generate the Pub/Sub message. Only messages published after the successful creation of a subscription are guaranteed to be received by subscribers for that subscription.
A single pull request with returnImmediately set to true is unlikely to return any messages, even if a message has been published. With this property set, if there are no messages immediately in memory of the server reached, the empty response is returned. You should always set returnImmediately to false. This still won't guarantee that messages are returned in a single request/response, even if there are messages available, but it will make it more likely.
Ideally, you would use the asynchronous client library, which opens a stream to the Cloud Pub/Sub service and receives messages as soon as they are available. If you are going to use the synchronous Pull method directly, then you need to keep many of them outstanding simultaneously in order to ensure delivery of messages with minimal latency. As soon as you receive a PullResponse for any of the outstanding requests, you should immediately open up another request to replace it. The goal of the asynchronous client library is to prevent one from having to take all of these step manually to ensure efficient delivery.
I have a piece of code that was scrounged together from another code that is known working. What it does is searches a column using textfinder for a value, in this case, yesterday's date, if nothing is found, it should send an email.
function findAndSendMail() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('FormResponses');
var ss2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('AlertDate');
var search = ss2.getRange("B2").getValue(); //cell has yesterday's date
var lastRow = ss.getLastRow();
var range = ss.getRange(1,4,lastRow); //define range for column D, column D contains dates
//find all occurrences of search key in column D and push range to array
var ranges = range.createTextFinder(search).findAll();
if (ranges!==null) {
var message = '';
}else {
var message = 'Test';
}
var emailRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("EmailGroup").getRange("A1");
var emailAddress = emailRange.getValues();
var subject = 'Subject';
var link = "blahblahblah"
if (message) {
MailApp.sendEmail(emailAddress, subject, '**This is an automated message**\n\n' + message + '\n\n**This is an automated message**\n' + link);
}
}
As you see, it should search column D, then, if it finds something, the message variable will be blank, else if it finds nothing, it will send an email to the email addresses chosen. I'm not sure how the results from a textfinder work with this and I think the way it is written is incorrect. Any help is appreciated, unfortunately, I cannot share the document in question as my company doesn't allow sharing outside of the domain. Thank you!
Try this:
You will need to update the sheet names I moved them to end of the line comments
function findAndSendMail() {
var ss=SpreadsheetApp.getActive()
var sh1=ss.getSheetByName('Sheet1');//FormResponses
var sh2=ss.getSheetByName('Sheet2');//AlertDate
var d1=new Date(sh2.getRange("B2").getValue()); //cell has yesterday's date
var d2=new Date(d1.getFullYear(),d1.getMonth(),d1.getDate()).valueOf();
var rg1 = sh1.getRange(1,4,sh1.getLastRow(),1);
var vA=rg1.getValues().map(function(r){
var dt=new Date(r[0]);
var dtv=new Date(dt.getFullYear(),dt.getMonth(),dt.getDate()).valueOf();
return dtv;
});
if(vA.indexOf(d2)==-1) {
var message='test';
var emailAddress = ss.getSheetByName("Sheet3").getRange("A1").getValue();//EmailGroup
var subject = 'Subject';
var link = "blahblahblah"
}
if (message) {
MailApp.sendEmail(emailAddress, subject, '**This is an automated message**\n\n' + message + '\n\n**This is an automated message**\n' + link);
//SpreadsheetApp.getUi().alert('I found something');//just for testing
}
}
This version sends an email if yesterday is not found.
In answer to you last question:
function findAndSendMail() {
var ss=SpreadsheetApp.getActive()
var sh1=ss.getSheetByName('Sheet1');//FormResponses
var sh2=ss.getSheetByName('Sheet2');//AlertDate
var d1=new Date(sh2.getRange("B2").getValue()); //cell has yesterday's date
if(isDate(d1)) {
var d2=new Date(d1.getFullYear(),d1.getMonth(),d1.getDate()).valueOf();
var rg1 = sh1.getRange(1,4,sh1.getLastRow(),1);
var vA=rg1.getValues().map(function(r){
var dt=new Date(r[0]);
var dtv=new Date(dt.getFullYear(),dt.getMonth(),dt.getDate()).valueOf();
return dtv;
});
if(vA.indexOf(d2)==-1) {
var message='test';
var emailAddress = ss.getSheetByName("Sheet3").getRange("A1").getValue();//EmailGroup
var subject = 'Subject';
var link = "blahblahblah"
}
if (message) {
MailApp.sendEmail(emailAddress, subject, '**This is an automated message**\n\n' + message + '\n\n**This is an automated message**\n' + link);
//SpreadsheetApp.getUi().alert('I found something');//just for testing
}
}else{
SpreadsheetApp.getUi().alert('Data is sheet2!B2 is not a date')
return;
}
}
function isDate(date){
return(Object.prototype.toString.call(date) === '[object Date]');
}
Here is my code and I can't figure out why replaceText() isn't working.
function createDoc(){
var templateid = "1jM-6Qvy47gQ45u88WfDU_RvfuSTsw27zBP_9MfsUGr8"; // get template file id
var FOLDER_NAME = "Completed Rental Agreements"; // folder name of where to put doc
// get the data from an individual user
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var data = sheet.getRange(2, 1, sheet.getLastRow()-1,sheet.getLastColumn()).getValues();
var lastRow = sheet.getLastRow();
var firstName = sheet.getRange(lastRow, 2, 1,1).getValues();
var lastName = sheet.getRange(lastRow, 3, 1,1).getValues();
var guestEmail = sheet.getRange(lastRow, 7, 1,1).getValues();
var companyEmail = "bearlakeprojectmanagement#yahoo.com";
var companyName = "Bear Lake Project Management";
var username = "jared.hislop.test#gmail.com"; // get their email (from sheet name)
var me = "jared.hislop.test#gmail.com";
//Copy Template
var docid = DocsList.getFileById(templateid).makeCopy("Rental Agreement - "+firstName+""+lastName+"-"+guestEmail).getId();
// var file = DocsList.getFileById(docid).addEditors(me);
// move file to right folder
var file = DocsList.getFileById(docid);
var folder = DocsList.getFolder(FOLDER_NAME);
file.addToFolder(folder);
var doc = DocumentApp.openById(docid);
var body = doc.getActiveSection();
var body_text = doc.addEditor("jared.hislop.test#gmail.com");
// Append Cabin Rules
// doc.appendParagraph("This is a typical paragraph.");
body.replaceText("/^companyEmail$/", "test");
body.replaceText("%companyName%", "test1");
body.replaceText("%todayDate%", "test1");
doc.saveAndClose();
}
I've tried doc.replaceText and body.replaceText along with several other options.
Any ideas why this isn't working?
Thank in advance
Consider this:
body.replaceText("%companyName%", "test1");
That will look for every instance of "companyName" with "%" on either side of it. The "%" in this case is just that, a piece of punctuation in a strange place. This is a convention used to decrease the likelihood of accidentally replacing real text in the document.
Your template document must have that exact pattern for the replacement to work. (Yours doesn't... instead you have just "companyName". Change it to "%companyName%".) Apply that rule for any other replacement you want to make.
You could benefit from some optimization.
...
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
// Next line is hard to maintain - there's a better way.
// var data = sheet.getRange(2, 1, sheet.getLastRow()-1,sheet.getLastColumn()).getValues();
// Read whole spreadsheet, skip headers
var data = sheet.getDataRange().getValues().slice(1);
// Already read in all data, use it instead of reading sheet again.
var firstName = data[data.length-1][2-1]; // (2-1) because array counts from 0
var lastName = data[data.length-1][3-1]; // while spreadsheet columns from 1
var guestEmail = data[data.length-1][7-1]; // Better: put these into variables.
...
While experimenting with your code, I ran into an autocompletion issue with doc.getActiveSection(). It turns out that there has been a recent change, according to the release notes for April 15 2013.
Renamed Document.getActiveSection() to getBody().
You should update your code accordingly.