Google Apps - Share Contacts within Org - google-apps

Within our Google Apps Org, I would like to setup a shared contact list that anyone inside our company can access and add/edit the contacts so we have all the same information. What is the best way to go about this?

I would create an application in App Engine that uses the Google APIs to edit the Shared Contacts list. That way you can restrict access to your domain users and also audit the activity that is occurring. There are third party tools out there that can edit the shared contact list but this is typically locked down to avoid situations where users delete contacts they should not be able to. Don't forget that the Shared Contacts list that appears in Gmail's type-ahead has a 24 hour delay.

Hey for anyone out there we used a Google Sheet, now anyone can update the sheet and you can either set an automated trigger to upload them on a schedule or manually push them into the Google Directory.
gsheet:
First we pull all the contacts from the directory then you can add/update/delete existing or new contacts.
Then push them to the Directory using the menu.
We made setup super simple so it auto grabs the user info and domain etc without the user having to do anything
var SHEET_NAME = 'google';
var ERROR_RECIPIENT_MAIL= Session.getActiveUser().getEmail();
var DOMAIN = ERROR_RECIPIENT_MAIL.replace(/.*#/, "");
Then we call the Domain Shared Contacts API to get all the data and put it into an array:
function getAllContacts(){
var contacts = ContactsApp.getContacts();
var lastRow = SpreadsheetApp.getActiveSpreadsheet().
getSheetByName(SHEET_NAME).getLastRow();
if (lastRow >2) SpreadsheetApp.getActiveSpreadsheet().
getSheetByName(SHEET_NAME).deleteRows(3, lastRow*1-2);
var contacts = ContactsApp.getContacts();
var params = {
method : "get",
contentType : "application/atom+xml",
headers : {"Authorization": "Bearer " +
ScriptApp.getOAuthToken(),"GData-Version": "3.0"},
muteHttpExceptions : true
};
var startIndex=1;
var data,respCode,resp;
resp = UrlFetchApp.fetch("//www.google.com/m8/feeds/contacts/"
+DOMAIN+"/full?alt=json&start-index="+startIndex, params);
respCode=resp.getResponseCode();
//SpreadsheetApp.getActiveSpreadsheet().
// getSheetByName(SHEET_NAME).getRange("A10").setValue(resp);
data = JSON.parse(resp.getContentText());
From there it's then put in the correct fields on the sheet for the user to update. Then the user selects the action from the drop down which calls the appropriate function when the script is run to update.
Example of delete function:
function deleteContact(contactID,rowNumber){
var params = {
method : "delete",
contentType : "application/json",
headers : {"Authorization": "Bearer " + ScriptApp.getOAuthToken(),"GData-Version": "3.0","If-Match":"*"}
};
var resp = UrlFetchApp.fetch(contactID, params);
var respCode=resp.getResponseCode();
if (respCode=='201' || respCode=='200') {
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME).deleteRow(rowNumber*1);
}
else{
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME).getRange(rowNumber*1, 15, 1, 1).setValue('ERROR');
ERROR_COUNT=ERROR_COUNT.toString()+rowNumber;
}
}
It's pretty cool, and now we are working on bulk data entry as it seems to stall or stop after about 700 contacts in a single run. Also some of the contacts don't get synced and have an error which we'll work on shortly to get the user more info and even store the missed contact to be fixed and updated after. Anyway hope that helps and gives you some ideas.
Ours is located here for anyone interested.

Related

send email from currently logged in user when checkbox is TRUE

My question is an extension of this fantastic solution but am hoping to take it one step further. Whenever a user other than me marks the checkbox as TRUE, the sender of the email is always me, since:
Installable triggers always run under the account of the person who created them
Is it possible to capture the user currently logged in and make them the sender, and if so, what am I missing in my code to make that happen?
What I've tried
I believed I had found my answer, but no such luck. This still posts the timestamp to the sheet successfully, but the email sender still shows as me. Any help would be greatly appreciated.
Edit(s):
I noticed in the above solution if (activeUser === effectiveUser) { only "worked" if typed as if (activeUser !== effectiveUser) {. In my attempts at making it work, I made that edit and forgot to revert it.
function sendEmail(e){
var sheet = e.source.getActiveSheet();
var cell = e.range;
var activeUser = Session.getActiveUser().getEmail();
var effectiveUser = Session.getEffectiveUser().getEmail();
if (activeUser !== effectiveUser) {
Logger.log(cell.getColumn());
Logger.log(cell.isChecked());
//Check if the checkbox in column G(index 7) was checked
if(sheet.getName() == "actionItems" && cell.getColumn() == 7 && cell.isChecked()){
//get current row values from column A to column F
var values = sheet.getRange(cell.getRow(),1,1,6).getDisplayValues().flat();
Logger.log(values);
var transmittalNumber = values[0];
var email = values[5];
var query = values[1];
//create and update the email's hmtl body
var templ = HtmlService.createTemplateFromFile('html_template');
templ.query = query;
var message = templ.evaluate().getContent();
//Send email
MailApp.sendEmail({
to: email,
subject: "Oatsies Action Item: "+transmittalNumber,
htmlBody: message
});
//Add timestamp at column H(index 8)
var timeZone = "GMT-7";
var date = Utilities.formatDate(new Date(),timeZone, "yyyy-MM-dd HH:mm");
sheet.getRange(cell.getRow(),8).setValue(date);
}
}
}
From the question
Is it possible to capture the user currently logged in and make them the sender?
If you are using a free Google account (usually gmail.com account) it might be possible if you use the Gmail API and set a way for active users to authorize the access to their Gmail account to send emails. Also it might be possible if you and the user are using a Google Workspace accounts and if you are able to take advantage of company-wide delegation of authority (also might be possible if you are able to configure the user's email addresses as emails aliases of your account).
Regarding the use of Session.getActiveUser().getEmail() it will return the active user email based on a complex rules i.e. your account and active user belongs to the same Google Workspace domains.
Related
Session.getActiveUser().getEmail() results are inconsistent
Domain-wide delegation
getActiveUser() doesn't return the user?

Getting to UM voicemail greetings for users in o365 using PowerShell or EWS

Hopefully a simple question - at one time I know when user's recorded their personal greetings for UM voicemail in o365 (regular greeting and/or extended absence greeting) these were stored in their Exchange inbox using a special item type (i.e. "IPM.Configuration.Um.CustomGreetings.External"). However setting up my test o365 setup, getting UM configured and all that, after recording my personal greeting and going through each item starting from the root of my inbox, (some 900+ items - lots of odd stuff in there) - I don't see anything like this any more. Lots of log, activity items, some messages but nothing about greetings. Extracting everything that could cast to an email type to a folder I went through each one - nothing promising.
anyone have any clues where the custom greetings for users UM (not auto attendant recordings - that's a different beast) has gone off to and how to get to it?
thanks much.
Got this working after a bit of flailing.
Ben Lye's post that Glen Scales provided in the comments above was what got me from A to B - Thanks Glen.
http://www.onesimplescript.com/2015/07/getting-um-voicemail-greetings-in.html
In related news Glen's very excellent PowerShell plug in for FAI exploration was also very helpful and can save you a bunch of time ramping up on the Folder Associated Information:
https://gsexdev.blogspot.com/2018/03/ews-fai-module-for-browsing-and.html
For those stumbling around with this in .NET using EWS, here's a quick stripped down blurb of code for fetching the standard and extended greeting recordings for a user - took me longer to slog through this than it should have, perhaps this can save someone a bit of time down the road:
note to run this against multiple mailboxes you'll need to have configured impersonation for your account you're authenticating with for EWS functions.
ExchangeService _service;
_service = new ExchangeService(ExchangeVersion.Exchange2016); // Exchange2013_SP1);
_service.Credentials = new WebCredentials("user#domain", "myPw");
_service.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
//select the user you're fetching greetings for
_service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "user#domain");
//get the root folder for the current account
var oParamList = new List<FolderId> {WellKnownFolderName.Root};
var oTemp = _service.BindToFolders(oParamList, PropertySet.FirstClassProperties);
var oRoot = oTemp.First().Folder;
var oView = new ItemView(50)
{
PropertySet = new PropertySet(BasePropertySet.FirstClassProperties),
Traversal = ItemTraversal.Associated
};
SearchFilter oGreetingFilter = new SearchFilter.ContainsSubstring(ItemSchema.ItemClass,
"IPM.Configuration.Um.CustomGreetings", ContainmentMode.Substring, ComparisonMode.IgnoreCase);
var oResults = _service.FindItems(oRoot.Id, oGreetingFilter, oView);
//fetch the binary for the greetings as values
var oPropSet = new PropertySet(BasePropertySet.FirstClassProperties);
var oRoamingBinary = new ExtendedPropertyDefinition(31753, MapiPropertyType.Binary);
oPropSet.Add(oRoamingBinary);
_service.LoadPropertiesForItems(oResults, oPropSet);
var strFileName = "";
foreach (var oItem in oResults.Items)
{
if (oItem.ItemClass.Equals("IPM.Configuration.Um.CustomGreetings.External",
StringComparison.InvariantCultureIgnoreCase))
strFileName = "jlindborg_Standard.wav";
if (oItem.ItemClass.Equals("IPM.Configuration.Um.CustomGreetings.Oof",
StringComparison.InvariantCultureIgnoreCase))
strFileName = "jlindborg_Extended.wav";
File.WriteAllBytes("d:\\" + strFileName, (byte[]) oItem.ExtendedProperties.First().Value);
}
}

Add Email Signature to Email Notification Script

I am writing a code on Google Apps Script to send an email every time there is a new announcement made in my site. Here is the code for reference:
var url_of_announcements_page = "https://sites.google.com/announcements";
var who_to_email = "emailaccount";
function emailAnnouncements(){
var page = SitesApp.getPageByUrl(url_of_announcements_page);
if(page.getPageType() == SitesApp.PageType.ANNOUNCEMENTS_PAGE){
var announcements = page.getAnnouncements({ start: 0,
max: 10,
includeDrafts: false,
includeDeleted: false});
announcements.reverse();
for(var i in announcements) {
var ann = announcements[i];
var updated = ann.getLastUpdated().getTime();
if (updated > PropertiesService.getScriptProperties().getProperty("last-update")){
var options = {};
options.htmlBody = Utilities.formatString("<h1><a href='%s'>%s</a></h1>%s", ann.getUrl(), ann.getTitle(), ann.getHtmlContent());
MailApp.sendEmail(who_to_email, "Announcement - '"+ann.getTitle()+"'", ann.getTextContent()+"\n\n"+ann.getUrl(), options);
PropertiesService.getScriptProperties().setProperty('last-update',updated);
}
}
}
}
function setup(){
PropertiesService.getScriptProperties().setProperty('last-update',new Date().getTime());
}
I would like to know if it is possible to add my gmail signature to the code. As when I send it with the script my signature is removed. Do I have to make my signature in the code or am i able to get my signature from gmail and automatically insert it at the end? Here is the line for the formatting of the email:
MailApp.sendEmail(who_to_email, "Announcement - '"+ann.getTitle()+"'", ann.getTextContent()+"\n\n"+ann.getUrl(), options);
Apps Script cannot access user's signature: there is no method for that in MailApp, or GmailApp, or even in Gmail API accessible via Advanced Google Services.
In principle, you could use GmailApp to get a recent outgoing message and search its text for the signature contained after the last -- found in message body. But this requires giving the script a lot more access (GmailApp can access, forward and delete existing email, unlike MailApp) and is error-prone (when text parsing fails, you might end up with an embarrassing fragment of text in your message).
Just append it directly:
var signature = "\n\n--\nFirstName LastName";
// ...
MailApp.sendEmail(... +signature, options);
(By the way, Gmail web interface and Gmail mobile app have different user signatures in general, so having another one for script-generated messages doesn't seem unusual.)

How to fix this authorization Google Apps Script suggest box library issue?

I'm trying to add an autocomplete feature (a Ui in a popup window in a spreadsheet) in my Google Spreadsheet using this Google Apps Script suggest box library from Romain Vialard and James Ferreira's book (modified):
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "my_sheet" ) { //checks that we're on the correct sheet
var r = s.getActiveCell();
if( r.getColumn() == 1) {
var names = ["Adam", "Peter", "Benjamin", "Ceaser", "Prometheus", "Gandi", "Gotama", "Mickey Mouse"];
var app = UiApp.createApplication();
var suggestBox = SuggestBoxCreator.createSuggestBox(app, 'contactPicker', 200, names);
app.add(suggestBox);
SpreadsheetApp.getActive().show(app);
var dataCell0 = r.offset(0, 1);
var dataCell0 = r.offset(0, 1);
if( dataCell0.getValue() == '' )
otherTestTunction();
}
}
}
But when I start editing column 1 of "my_sheet" and the Ui box appears, this autorization error happens (In my language it says: "you must have permission to perform this action"):
The documentation says that onEdit() trigger "They cannot access any services that require authentication as that user. For example, the Google Translate service is anonymous and can be accessed by the simple triggers. Google Calendar, Gmail, and Sites are not anonymous and the simple triggers cannot access those services."
Since I'm not using ContactsApp, I suppose that the suggest box library require authorization.
How could I set up an installable on Edit trigger that will ask for authorization? (Could you give me some code sample?)
Here is my test spreadsheet: https://docs.google.com/spreadsheet/ccc?key=0AtHEC6UUJ_rsdFBWMkhfWUQ0MEs2ck5OY1BsYjRSLXc&usp=drive_web#gid=0
Out of curiosity about what you suggested on authorizations needed by the library I made a test on a new sheet, the exact code below asks for spreadsheet access, nothing more.
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
var names = ["Adam", "Peter", "Benjamin", "Ceaser", "Prometheus", "Gandi", "Gotama", "Mickey Mouse"];
var app = UiApp.createApplication();
var suggestBox = SuggestBoxCreator.createSuggestBox(app, 'contactPicker', 200, names);
app.add(suggestBox);
SpreadsheetApp.getActive().show(app);
var dataCell0 = r.offset(0, 1);
}
To handle that you just have to ask your user to run one function in your script (no matter what function) and they will get the following popup :
After this initial step your function will work as expected, ie the Ui will show up.
Beside that, I'm not sure I understand what you want to achieve is feasible, the onEdit trigger fires when the edit is done, meaning after you hit ENTER, then the value in the suggestBox is not taken into account... moreover you have to handler in the UI to do anything so I'm still wondering what do you really expect to do with this code ? (what would be ideal is an onClick event in spreadsheetApp but unfortunately it doesn't exist so far...)
But maybe I missed something obvious.
About installable onEdit that you mention also in your post, you should note that it doesn't need to be authorized by the end user since it would run as YOU, the person that creates the trigger and not the user accessing the SS , therefor accessing your own data and not the user's ones... That might be a non negligible restriction (as Zig mentioned in a comment earlier...)

setting up script to include google docs form data in email notification

I've setup a form using googledocs. I just want to have the actual data entered into the form emailed to me, as opposed to the generic response advising that the form has been completed.
I have no skill or experience with code etc, but was sure i could get this sorted. I've spent hours+hours and haven't had any luck.
My form is really basic.it has 5 fields. 4 of which are just text responses, and one multiple choice.
I found this tute online (http://www.labnol.org/internet/google-docs-email-form/20884/) which i think sums up what i'm trying to do, but have not been able to get it to work.
from this site i entered the following code:
function sendFormByEmail(e)
{
var email = "reports.mckeir#gmail.com";
var subject = "Google Docs Form Submitted";
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var message = "";
for(var i in headers)
message += headers[i] + ' = '+ e.namedValues[headers[i]].toString() + "\n\n";
MailApp.sendEmail(email, subject, message);
}
To this, i get the following response: ->
Your script, Contact Us Form Mailer, has recently failed to finish successfully. A summary of the failure(s) is shown below. To configure the triggers for this script, or change your setting for receiving future failure notifications, click here.
The script is used by the document 100% Club.
Details:
Start Function Error Message Trigger End
12/3/12 11:06 PM sendFormByEmail TypeError: Cannot call method "toString" of undefined. (line 12) formSubmit 12/3/12 11:06 PM
Is anyone able to help shed some light on this for me? I'm guessing i'm not including some data neeeded, but i honestly have no clue.
Workaround http://www.labnol.org/internet/google-docs-email-form/20884/
You have to setup app script to forward the data as email.
I'll point to the comment above that solved it for me: https://stackoverflow.com/a/14576983/134335
I took that post a step further:
I removed the normal notification. The app script makes that generic text redundant and useless now
I modified the script to actually parse the results and build the response accordingly.
function sendFormByEmail(e)
{
var toEmail = "changeme";
var name = "";
var email = "";
// Optional but change the following variable
// to have a custom subject for Google Docs emails
var subject = "Google Docs Form Submitted";
var message = "";
// The variable e holds all the form values in an array.
// Loop through the array and append values to the body.
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
// Credit to Henrique Abreu for fixing the sort order
for(var i in headers) {
if (headers[i] = "Name") {
name = e.namedValues[headers[i]].toString();
}
if (headers[i] = "Email") {
email = e.namedValues[headers[i]].toString();
}
if (headers[i] = "Subject") {
subject = e.namedValues[headers[i]].toString();
}
if (headers[i] = "Message") {
message = e.namedValues[headers[i]].toString();
}
}
// See https://developers.google.com/apps-script/reference/mail/mail-app#sendEmail(String,String,String,Object)
var mailOptions = {
name: name,
replyTo: email,
};
// This is the MailApp service of Google Apps Script
// that sends the email. You can also use GmailApp here.
MailApp.sendEmail(toEmail, subject, message, mailOptions);
// Watch the following video for details
// http://youtu.be/z6klwUxRwQI
// By Amit Agarwal - www.labnol.org
}
The script utilized in the example is extremely generic but very resilient to change because the message is built as a key/value pair of the form fields submitted.
If you use my script you'll have to tweak the for loop if statements to match your fields verbatim. You'll also want to edit the toEmail variable.
Thanks again for the question and answers. I was about to ditch Google Forms as the generic response was never enough for what I was trying to do.
Lastly, in response to the actual problem above "toString of undefined" specifically means one of the form fields was submitted as blank. If I had to guess, I would say the author only used this for forms where all the fields were required or a quick undefined check would've been put in place.
Something like the following would work:
for(var i in headers) {
var formValue = e.namedValues[headers[i]];
var formValueText = "";
if (typeof(formValue) != "undefined") {
formValueText = formValue.toString();
}
message += headers[i] + ' = '+ formvalueText + "\n\n";
}
I haven't tested this precisely but it's a pretty standard way of making sure the object is defined before trying methods like toString() that clearly won't work.
This would also explain Jon Fila's answer. The script blindly assumes all of the header rows in the response are sent by the form. If any of the fields aren't required or the spreadsheet has fields that are no longer in the form, you'll get a lot of undefined objects.
The script could've been coded better but I won't fault the author as it was clearly meant to be a proof of concept only. The fact that they mention the replyTo correction but don't give any examples on implementing it made it perfectly clear.
If this is a Google Form, do you have any extra columns in your spreadsheet that are not on the form? If you delete those extra columns then it started working for me.
You don't need to use a script. Simply go to Tools >> Notification Rules on your Google Spreadsheet. There you can change the settings to receive an email with your desired information every time the document is changed.