Get gmail message hyperlink using Apps Script - google-apps-script

I'm trying to get the Url of Gmail messages and store them into a Google Sheet. I'm doing this because the sheet will serve as a dashboard and I want to be able to link to specific messages which can be quickly opened by clicking the message hyperlink.
Gmail message urls will start with something like "https://mail.google.com/mail/u/0/?pli=1#inbox/" for messages in the 'inbox' followed by a string of around 70 characters representing a message ID such as "ZhatKJWQfkVxNWLWSctJlTPzJAjLTGmHOFwlqPWVTvjkwVgsnhBsfmJrrvjRDAHfKozQnYn".
As far as I can tell there is no way to get the full url from the GMail Message class. However you can retrieve the message id using getId().
So my approach was to retrieve the ID, append it to the inbox prefix ("https://mail.google.com/mail/u/0/?pli=1#inbox/") and that should create the link as follows:
for (var x = messageThread.length-1; x>=0; x--) {
for (var y = 0; y< numMessagesInThread; y++) {
var message = messageThread[x].getMessages()[y];
var messageId = message.getId();
var messageUrl = "https://mail.google.com/mail/u/0/?pli=1#inbox/" + messageId;
...
The problem is it turns out getId() doesn't return the 70 character Id in the original Url of the message but rather a 16 character Id such as "2487g294ie3f3x8z". Needless to say when used in the URL it doesn't work.
I'm stuck at this point and have been searching for a way to do this, if anyone has ideas would be greatly appreciated.

Related

How to find Google Form ID

Update! The Form ID is in the web address.
Someone kindly pointed out to me (outside of Stack Overflow) that the Form ID which identifies the form can be found in the web address. Example:
https://docs.google.com/forms/d/1y9XMjvZi_wlFC2FN64cdafIyGuM_7UOsn1Q61PXv5MQ/edit
Where the bolded text is the Form ID.
Original:
Apologies in advance, as I am not an experienced script writer and may use improper jargon.
But - I found the response to this question when googling about how to find the Form ID element in a Google Form, but the answer is old and my problem is similar. I have tried searching the "Inspect Element" data and still cannot identify the ID attribute. I've tried searching the code for:
data-item-id="##########", or
aria-describedby="i.desc.########## i3"
for="entry_XXXXXXX"
Still no luck. Does anyone have an updated suggestion for finding the Form ID? For reference, I am using the script below as my starting point. This is taken from a different/old form, but is similar in functionality so I was hoping to leverage it. I am trying to find my Form's ID (such as that as in line 6-7).
/**
* #NotOnlyCurrentDoc
* Limit OAuth scope to only current spreadsheet rather than all sheets in drive
*/
function onSubmit(e) {
var form = FormApp.openById('1eccBQ7Bs34Z54keGHeR8HDXmiP1UqxMi9vSDWNv6zgs');
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Master');
var data = sheet.getDataRange().getValues();
//var urlCol = 26;
var responses = form.getResponses();
var timestamps = [], urls = [], resultUrls = [];
for (var i = 0; i < responses.length; i++) {
timestamps.push(responses[i].getTimestamp().setMilliseconds(0));
urls.push(responses[i].getEditResponseUrl());
}
for (var j = 1; j < data.length; j++) {
resultUrls.push([data[j][0]?urls[timestamps.indexOf(data[j][0].setMilliseconds(0))]:'']);
}
sheet.getRange(2, urlCol = 27, resultUrls.length).setValues(resultUrls);
return resultUrls;
};
As the OP mentioned in the question body, the Form ID could be found in the Google Form URL, but hte OP missed to mention that this URL is the edit URL, not the "view" URL.
The form owner also could find the form ID by using the web-browser developer tools by searching for data-redirect-url which has assigned the Form URL:
data-redirect-url="https://docs.google.com/forms/d/form_id/edit?usp=redirect_edit_m2"
As mentioned by the OP the Form ID is between https://docs.google.com/forms/d/and /edit.
Besides looking at the Form URL, the form ID could be retrieved by using Google Apps Script. The easier way is to use a bounded script similar to this:
function getActiveFormID(){
const id = FormApp.getActiveForm().getId();
console.log(id);
}
Another way is by using the Drive Service. The following example assumes that there is only one file named "My Form":
function getFormId(){
const id = DriveApp.searchFiles(`title contains "My Form"`).next().getId();
console.log(id);
}
From Google Chrome, open the form (view mode, not edit).
Hit F12.
In the Elements window pain,
expand <body>
expand <script type = "text/javascript" nonce> == $0
You should see:
var FB_PUBLIC_LOAD_DATA with each element you created on their form and their respective Element ID.

Number object from http request returns date type or similar

I make a Facebook API call in Google scripts to get the share count for a URL. It appears that the number (e.g. 31) is being found correctly, but when I pass it to Sheets, it shows e.g. 30/01/1900 in the sheets box.
My appScript code is:
function getShareCount(url) {
var url = "https://any.org/111";
var inputurl = "https://graph.facebook.com/v2.1/?id=" + url + "&access_token=XXXXXXXX";
var response = UrlFetchApp.fetch(inputurl);
var response = JSON.parse(response.getContentText());
var response = response.share.share_count;
Utilities.sleep(500);
return response;
}
and the spreadsheet box has: "=getShareCount(B2)"
If I purposefully break the code and run the debugger in script Apps, I can see that script apps is getting a response with Number: 31. If I change to e.g. "response.id", the URL is returned into sheets as expected. The same with other parts of the object. Those are strings, and this is a number. I can't work out what sort of object sheets is receiving, nor what method I can use to simply show the number `311.
Any ideas? Thanks!
It seems that your cell has a custom format of Date. Select the cells you want to format and click Format > Number > Automatic

When using the FormResponse class, a unexpected Id is returned for a response depending on how the response is retrieved

I'm hoping someone has seen this before, I'm using Google Forms, and on submission, using Google Apps Script to store the response id in a separate Spreadsheet in order to store further meta data in the future (Id gained from the method in the onSubmit event response e.response.getId()). Upon the first submission of a Google Form, I logged the response ID in a new sheet.
I can load the response through form.getResponse(responseIdStoredInSheet), however, when I loop through the responses returned by form.getResponses() and call .getId() on those FormResponses returned, the Id is slightly altered at the end. I've searched for an afternoon around the docs and online as to why this happens, but to no avail.
function testResponseIds()
{
var responseIdStoredInSheet = 'ChMxNzM4MDQzNzQ5MjQyNDc0Njg4EAA';
//only response in the form
var formResponse = form.getResponse(responseIdStoredInSheet);
//outputs as expected above - ChMxNzM4MDQzNzQ5MjQyNDc0Njg4EAA
Logger.log(formResponse.getId());
//loop through all responses (only above response is present)
var formResponses = form.getResponses();
for (var i = 0; i < formResponses.length; i++)
{
//Outputs slightly different Id - ChMxNzM4MDQzNzQ5MjQyNDc0Njg4EJ2kvMHLzsOvdg
Logger.log(formResponses[i].getId());
}
}
Logged output from above:
[14-03-03 17:12:51:259 GMT] ChMxNzM4MDQzNzQ5MjQyNDc0Njg4EAA
[14-03-03 17:12:51:279 GMT] ChMxNzM4MDQzNzQ5MjQyNDc0Njg4EJ2kvMHLzsOvdg
I tested your code on one of my form and it look to be working as intented. My supposition is that you deleted the answer you are trying to retrieve but you can still get it through the script(I don't know the reason, the cache I suppose).
What I can propose you is to retrieve the edit URL so you will see that it's not the same answer (modifying it and checking the form answers).
Logger.log(formResponses[i].getEditResponseUrl());
By the way in your posted script you forgot:
var form = FormApp.getActiveForm();
or the equivalent (couldn't run your script without adding that line)

How to generate a pre-filled form URL for Google Form

I'm looking for a programmatic way to automate the generation of pre-filled URLs for google forms.
In a recent update, Google introduced a new Forms product to Google Docs. If you open the tools menu in a spreadsheet, you'll see some new options.
In the new Form Responses menu, one option is "Get pre-filled URL". This opens up a dialog containing a version of your form that you can fill out, and when you submit it, you receive a URL that can be used to open a Live Form with the data you pre-filled ready and waiting for you. The URL looks something like this...
https://docs.google.com/forms/d/--Form-ID--/viewform?entry.1094330118=Something&entry.1471717973=stack#example.com&entry.540962741&entry.787941281&entry.1873343651
The questions from the form have a fixed identity, e.g. entry.1094330118. They may be pre-filled with a value (entry.1094330118=Something) or blank (entry.7879412).
In apps-script, I'd like to generate these pre-filled URLs for users of my form, so I can provide them for updates. My users are not members of an Apps Domain, so I don't have the option of embedding an Edit your response link.
If I can get the information about the form, I will be able to piece together the URL. While I can go through the UI to create one URL, and dissect it to get the info for that form, I want a solution that will work with arbitrary forms.
How can I programmatically determine the question IDs?
With the new
Forms product, is the form available to me through any apps-script
APIs? (I know about getFormURL() - that's not what I mean.)
Armed with a question ID, can I get more information about the question? (Question text, type, etc.)
I required something similar for users to go and edit their response, take a look here: http://productforums.google.com/forum/#!topic/docs/LSKKCR3VHC8
Copy / paste code below:
function assignEditUrls() {
var form = FormApp.openById('1MonO-uooYhARHsr0xxxxxxxxxxxxxxxxxxxxx');
//enter form ID here
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form Responses');
//Change the sheet name as appropriate
var data = sheet.getDataRange().getValues();
var urlCol = 4; // column number where URL's should be populated; A = 1, B = 2 etc
var responses = form.getResponses();
var timestamps = [], urls = [], resultUrls = [];
for (var i = 0; i < responses.length; i++) {
timestamps.push(responses[i].getTimestamp().setMilliseconds(0));
urls.push(responses[i].getEditResponseUrl());
}
for (var j = 1; j < data.length; j++) {
resultUrls.push([data[j][0]?urls[timestamps.indexOf(data[j][0].setMilliseconds(0))]:'']);
}
sheet.getRange(2, urlCol, resultUrls.length).setValues(resultUrls);
}
This is not possible right now but this request is being tracked on the Issue Tracker here. Please add your use cases there and watch it for updates.
I found no way to create a pre-filled URL from the form id itself. It is possible if the form has already an answer:
var form = FormApp.openById('1nGvvEzQHN1n-----_your_for_id_----zemoiYQA');
var responses = form.getResponses();
Logger.log(responses[0].toPrefilledUrl());
referring to this answer, it can be used to create prefilled urls, by replacing the last line like this:
instead of
FormResponse.submit();
it will be
FormResponse.toPrefilledUrl();

addEditors to Document from formSubmit

I'm Working on creating script that will perform the actions described below. so far, I've managed to get the first two parts to function, but am now stuck on getting anything more to work. I've reviewed several response forums and tried the suggestions, but no success.
Desired script flow:
form submitted from spreadsheet form
completes fields:
Timestamp
Username (email collected on submission)
Student
Grade
Intervention Plan
Core Reading/Math
Team (email list)
1 script runs onFormSubmit that then creates a copy of a template document, renames that new copy to the e.value "student" submitted in form,
2 then replaces selected text strings within the document with values submitted in the form.
3 Add editors to new document and sends notification with desired instructions
4 creates event (one week from submission date) event details include instructions and link to shared document for team members to complete with their input, sends event invitation to email list.
Here is the working script so far.
function formSubmitValues(e) {
var timeStamp = e.values[0];
var userEmail = e.values[1];
var student = e.values[2];
var grade = e.values[3];
var conern = e.values[4];
var readingCore = e.values[5];
var mathCore = e.values[6];
var interventions = e.values[7];
var team = e.values[8].toString(); // "just to be sure"..Henrique says add .toString this allowed the replaceText part to work
//Makes copy of template document and renames
var tempID = ("1Rq0pDAnuGNfL6W3GB0ZuLeWM2uYzHpKzoyxoXlwjtgE") // use document ID from Template Document
var copyId = DocsList
.getFileById(tempID)
.makeCopy(student + " Initial Referral") // names new copy as student's name
.getId();
// trying to add editors to new document using email list generated in form submit value of "team"
DocsList.getFileById(copyId).addEditors([team]);
// replaces text within template with selected fields from formSubmitValues
var doc = DocumentApp.openById(copyId)
var body = doc.getActiveSection();
body.replaceText("%STUDENT%", student);
body.replaceText("%DATE%", timeStamp);
body.replaceText("%TEACHER%", userEmail);
body.replaceText("%TEAM%", team);
return doc;
}
REPORTED ISSUE RESPONSE: Here is what they said: "The function takes an array or strings, like: DocsList.getFileById(copyId).addEditors(['parent#domain.com', 'parent2#domain.com']);
I tried entering emails directly into script like this and things worked.
So my problem is not the 'addEditors method, but lies in getting the form submitted emails to be passed correctly. Any suggestions on how I would do this?
I have tried what I believe to be all combinations of using .toString(), or not, and using .Split(',').
RE-DEFINE PROBLEM : So it is an issue of how the emails are passed from the e.values form submit.
Here is where I'm at:
When I type emails into script directly: .addEditors(['parent#domain.com', 'email2#domain.net', 'email3#gmail.com']) it works, (I did have to move the addEditors method in the script to go right after the .makeCopy instead of at the end.)
This is what the Execution Transcript shows:
File.addEditors([[parent#domain.com, email2#domain.net]]) and it runs the rest of the script. note: One part I don't understand is the single quotes i.e. 'email' They must be typed in the script, but don't show up on Transcript when run. I've tried putting them around emails in the form, but it makes them show in Transcript and still doesn't run anyway.
So this is what script looks like now:
var tempID = ("1Rq0pDAnuGNfL6W3GB0ZuLeWM2uYzHpKzoyxoXlwjtgE") // use document ID from Template Document
var copyId = DocsList
.getFileById(tempID)
.makeCopy(student + " - TestingCopy") // names new copy as student's name + text
.addEditors([team.split(',')])
.getId();
But when I use the var team with or without .split(',') it does not work. But in the Transcript it shows:
File.addEditors([[rreynolds#domain.net, parent#domain.com]])
which looks identical as to what shows when it does work, but that is the last thing shown in Transcript and editors are not added to document and the script does not finish.
I'm obviously not understanding something here. Is there a way I could get the emails in the team e.values to be treated in a way that the addEditors method is requiring? In the spreadsheet cell they appear as a CSV. i.e rreynolds#domain.net, parent#domain.com
Do they have to be read one at a time, or something?
I'm learning a lot, and appreciate all your help. I am sorry for the confusion with all the comments, but am not sure of the correct way to address issues in this forum. For example: should I go back and edit my original script to show the current version, or add it someplace else? I'm trying to keep the conversation flowing, so that it is easier for others to follow - Thanks rob
please let me give a last (hopefully) clear answer : (thanks for sharing the spreadsheet, this is far more easy to work on ;-)
here is your code fully working.
I have created some intermediate variables to show how it works.
function formSubmitEditors(e) {
// defines spreadsheet form events on submit of form. This function formSubmitEditors is triggered on formSubmit
var timeStamp = e.values[0];
var fileName = e.values[1];
var team = e.values[2].replace(/, /g,"|"); // remove unwanted spaces and commas replace by | for visibility ;-)
Logger.log(team);// contains | as separators
var teamArray = team.split('|');
Logger.log(teamArray.length+' : '+teamArray);// check that it is an array of x elements
//Makes copy of template document and renames
var tempID = '1Rq0pDAnuGNfL6W3GB0ZuLeWM2uYzHpKzoyxoXlwjtgE' // use document ID from Template Document
var copyId = DocsList
.getFileById(tempID)
.makeCopy(fileName + " - TestingCopy") // names new copy as student's name + text
.getId(); //
var file = DocsList.getFileById(copyId).addEditors(teamArray);
// replaces merged-text values within template with selected fields from formSubmitValues
var doc = DocumentApp.openById(copyId)
var body = doc.getActiveSection();
body.replaceText("%FILE%", fileName);// you wrote %FILENAME% in place of %FILE%
body.replaceText("%DATE%", timeStamp);
body.replaceText("%TEAM%", team);// it will be shown with | as separators, if you don't like it replace team by teamArray.toString() to get commas again.
}
EDIT : I removed the toString() for team event, not necessary since e.parameters are already strings.
EDIT2 : to be complete and do what you needed in the initial question you could replace the end of the code with this one that creates the Cal event on next week and sends invites with link to the doc.
var file = DocsList.getFileById(copyId).addEditors(editorsArray);
var fileurl = file.getUrl();
Logger.log(fileurl)
// replaces merged-text values within template with selected fields from formSubmitValues
var doc = DocumentApp.openById(copyId)
var body = doc.getActiveSection();
body.replaceText("%FILE%", fileName);
body.replaceText("%DATE%", timeStamp);
body.replaceText("%MAILS%", editors);
var Cal = CalendarApp.getCalendarsByName('testencodage')[0];// replace with your calendar name you want to use
var newEvent = Cal.createAllDayEvent('Fill the questionnary', new Date(new Date(newtimeStamp).getTime()+7*24*3600*1000), { guests : e.values[2] , sendInvites : true , description :"Don't forget to fill this document "+fileurl})
}
I'd suggest a couple of things
Add a few Logger.log statements in your code to print out debug information.
Add a try ... catch block around the entire section of code and print out the exception. See if you are getting any exception.
Last, use the Execution transcript window to see where your script stopped, if it did.
There are 2 ways to add an editor by email : addEditors([emailAddresses]) and addEditor(emailAddress)
The first has an "s" and needs an array of email adress strings, the second takes a single string as argument. You should use the second or add [brackets] to the email string in your code.
concerning you comment // need to figure out where/how to: .addEditors(email1,email2,etc);
// is this done from DocsList or DocumentApp class?
addEditor() and addEditors() belong to the file class, a member of DocsList class , you can add user(s) using user(s) objects or user(s) email(s) as explained in the doc.
It could be used like this DocFile.addEditors([email1,email2])
EDIT : A lot of comments on this post, sorry about that, it has become quite uneasy to read... I tested these addEditors feature with spreadsheet and it works as expected, using simple array for multiple user emails and string for single email. The document service seems to have a problem with the addEditor() method and it should be reported to the issue tracker.
REPORTED I've reported issue #1512 - Rocketrob