I do apologise for asking this here as there is already an existing thread but I was unsure of the correct protocol.
I need to use apps script to add a custom sendas address for my users in Gmail.
The thread here appears to do what I need: Creates a custom "from" send-as alias with GAS and APIs.
However I am new to Apps Script (especially advanced APIs) and am unsure which sections of Jay's script that I would need to update to make this work for me.
I know that I will need to update:
function createAlias() {
var userEmail = 'useraccount#example.com';
var alias = 'myalias#example.com';
var alias_name = 'Alias User';
But I am unsure what to update the following with or where to find it:
var service_account = {
"private_key": "-----BEGIN PRIVATE KEY...",
"client_email": "sa-email#example.com",
"client_id": "1234569343",
"user_email": "useraccount#example.com"
};
I was unable to comment on the existing post and it didn't seem appropriate to add my question as an answer. For convenience, I have pasted Jay's code here.
If anyone could please let me know which variables I will need to update with my specific information (and if necessary, where to find it) that would be much appreciated.
Kind Regards,
Brett
var service_account = {
"private_key": "-----BEGIN PRIVATE KEY...",
"client_email": "sa-email#example.com",
"client_id": "1234569343",
"user_email": "useraccount#example.com"
};
function getOAuthService(user) {
return OAuth2.createService('Service Account')
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(service_account.private_key)
.setIssuer(service_account.client_email)
.setSubject(service_account.user_email)
.setPropertyStore(PropertiesService.getScriptProperties())
.setScope('https://www.googleapis.com/auth/gmail.settings.sharing
https://www.googleapis.com/auth/gmail.settings.basic')
}
function createAlias() {
var userEmail = 'useraccount#example.com';
var alias = 'myalias#example.com';
var alias_name = 'Alias User';
var service = getOAuthService();
service.reset();
if (service.hasAccess()) {
var url = 'https://www.googleapis.com/gmail/v1/users/me/settings/sendAs'
var headers ={
"Authorization": 'Bearer ' + service.getAccessToken(),
"Accept":"application/json",
"Content-Type":"application/json",
};
var resource ={
'sendAsEmail': alias,
'displayName': alias_name
};
var options = {
'headers': headers,
'method': 'POST',
'payload': JSON.stringify(resource),
'muteHttpExceptions': true
};
Logger.log(options);
var response = UrlFetchApp.fetch(url, options);
Logger.log(response.getContentText());
}
}
function reset() {
var service = getOAuthService();
service.reset();
Related
I am using the following code to make requests to the Spotify API via Google Apps Script:
function search() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var artist = sheet.getRange(1,1).getValue();
artist = encodeURIComponent(artist.trim());
var result = searchSpotify(artist);
Logger.log(result);
}
function searchSpotify(artist) {
//searches spotify and returns artist ID
var response = UrlFetchApp.fetch("https://api.spotify.com/v1/search?q=" + artist + "&type=artist&limit=1",
{ method: "GET",
headers:{
"contentType": "application/json",
'Authorization': "Bearer BQBnpSUdaEweirImw23yh2DH8OGhTwh5a_VnY_fgb2BPML0KvFvYd04CaEdUhQN9N4ZUXMIVfJ1MjFe1_j0Gl0UoHDhcoC_dklluZyOkq8Bo6i2_wfxSbGzP3k5EUjUKuULAnmTwCdkdZQnl-SNU0Co"
},
});
json = response.getContentText();
var data = JSON.parse(json);
var uri = data.artists.items[0].uri.slice(15);
var getArtists = getRelatedArtists(uri);
Logger.log(getArtists);
return getArtists;
}
function getRelatedArtists(uri) {
//searches related artists with the returned ID
var response = UrlFetchApp.fetch("https://api.spotify.com/v1/artists/" + uri + "/related-artists",
{ method: "GET",
headers:{
"contentType": "application/json",
'Authorization': "Bearer BQBnpSUdaEweirImw23yh2DH8OGhTwh5a_VnY_fgb2BPML0KvFvYd04CaEdUhQN9N4ZUXMIVfJ1MjFe1_j0Gl0UoHDhcoC_dklluZyOkq8Bo6i2_wfxSbGzP3k5EUjUKuULAnmTwCdkdZQnl-SNU0Co"
},
});
json = response.getContentText();
var data = JSON.parse(json);
var listArtists = [];
for(var i = 0, len = data.artists.length; i < len; i++){
listArtists.push(data.artists[i].name);
}
return listArtists;
}
This works fine using the temporary Authorisation token from the Spotify website but this token refreshes every hour and so is obviously useless.
I am trying to use my own Authorisation token and ID which I have setup on Spotify however I'm struggling to make this work. As I understand it I may need to add an extra step at the beginning to start the authorisation process but I've tried all methods suggested but keep receiving server errors.
From the document, it seems that "Client Credentials Flow" uses the basic authorization.
In order to use this, at first, you are required to retrieve "client_id" and "client_secret".
Sample script:
var clientId = "### client id ###"; // Please set here.
var clientSecret = "### client secret ###"; // Please set here.
var url = "https://accounts.spotify.com/api/token";
var params = {
method: "post",
headers: {"Authorization" : "Basic " + Utilities.base64Encode(clientId + ":" + clientSecret)},
payload: {grant_type: "client_credentials"},
};
var res = UrlFetchApp.fetch(url, params);
Logger.log(res.getContentText())
From curl sample, grant_type is required to send as form.
Result:
The document says that the response is as follows.
{
"access_token": "NgCXRKc...MzYjw",
"token_type": "bearer",
"expires_in": 3600,
}
Note:
This is a simple sample script. So please modify this for your situation.
I prepared this sample script by the sample curl in the document.
Reference:
Client Credentials Flow
Edit:
As your next issue, you want to retrieve the access token from the returned value. If my understanding is correct, how about this modification? Please modify my script as follows.
From:
Logger.log(res.getContentText())
To:
var obj = JSON.parse(res.getContentText());
Logger.log(obj.access_token)
When the value is returned from API, it returns as a string. So it is required to parse it as an object using JSON.parse().
I am trying to follow documentation but never get the 0Auth2 to connect.
Btw I'm running the script manually from the google sheets scripting page, where should I get prompting for allowing access?
(I don't understand all this 0Auth2 scheme and I have already gave authorization to run the script and got client id and secret)...
See below my log and script routines (the first get to photo is still minimalistic as I didn't yet get through the 0Auth2 step ;-) .
Thanks in advance for any hint. I thought it would be trivial as it is my own sheet and google photo account...
Log:
[19-01-06 17:50:05:809 CET] starting
[19-01-06 17:50:05:810 CET] getPhotoService
[19-01-06 17:50:05:849 CET] false
[19-01-06 17:50:05:850 CET] redirectURI=https://script.google.com/macros/d/[REMOVED]/usercallback
[19-01-06 17:50:05:864 CET] Open the following URL and re-run the script: https://accounts.google.com/o/oauth2/auth?client_id=[removed].apps.googleusercontent.com&response_type=code&redirect_uri=https%3A%2F%2Fscript.google.com%2Fmacros%2Fd%2F[removed]%2Fusercallback&state=[removed]&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fphotoslibrary.readonly&login_hint=[removed]&access_type=offline&approval_prompt=force
Script:
function getPhotoService() {
// Create a new service with the given name. The name will be used when
// persisting the authorized token, so ensure it is unique within the
// scope of the property store.
Logger.log('getPhotoService');
return OAuth2.createService('gPHOTOfj')
// enable caching on the service, so as to not exhaust script's PropertiesService quotas
.setPropertyStore(PropertiesService.getUserProperties())
.setCache(CacheService.getUserCache())
// Set the endpoint URLs, which are the same for all Google services.
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the client ID and secret, from the Google Developers Console.
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
// Set the name of the callback function in the script referenced
// above that should be invoked to complete the OAuth flow.
.setCallbackFunction('authCallback')
//.setCallbackFunction('https://script.google.com/macros/d/'+SCRIPT_ID+'/authCallback')
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getUserProperties())
// Set the scopes to request (space-separated for Google services).
.setScope('https://www.googleapis.com/auth/photoslibrary.readonly')
// Below are Google-specific OAuth2 parameters.
// Sets the login hint, which will prevent the account chooser screen
// from being shown to users logged in with multiple accounts.
.setParam('login_hint', Session.getActiveUser().getEmail())
// Requests offline access.
.setParam('access_type', 'offline')
// Forces the approval prompt every time. This is useful for testing,
// but not desirable in a production application.
.setParam('approval_prompt', 'force');
}
function authCallback(request) {
Logger.log('Called back!');
var photoService = getPhotoService();
var isAuthorized = photoService.handleCallback(request);
if (isAuthorized) {
Logger.log('Authorisation Success!');
} else {
Logger.log('Authorisation Denied...!');
}
}
// Modified from http://ctrlq.org/code/20068-blogger-api-with-google-apps-script
function photoAPI() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var albums_sh = ss.getSheetByName("albums") || ss.insertSheet("albums", ss.getSheets().length);
albums_sh.clear(); var nrow = new Array(); var narray = new Array();
Logger.log("starting");
var service = getPhotoService();
Logger.log(service.hasAccess());
Logger.log('redirectURI='+service.getRedirectUri());
if (service.hasAccess()) {
var api = "https://photoslibrary.googleapis.com/v1/albums";
var headers = {
"Authorization": "Bearer " + service.getAccessToken()
};
var options = {
"headers": headers,
"method" : "GET",
"muteHttpExceptions": true
};
var response = UrlFetchApp.fetch(api, options);
var json = JSON.parse(response.getContentText());
for (var i in json.items) {
nrow = []; nrow.push(json.items[i].id); nrow.push(json.items[i].name); nrow.push(json.items[i].url); narray.push(nrow);
}
albums_sh.getRange(1,1,narray.length,narray[0].length).setValues(narray);
} else {
var authorizationUrl = service.getAuthorizationUrl();
Logger.log("Open the following URL and re-run the script: " + authorizationUrl);
}
}
So it works, if others want to use it. But it is quite slow (I have 500 albums...):
function photoAPI() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var albums_sh = ss.getSheetByName("albums") || ss.insertSheet("albums", ss.getSheets().length);
albums_sh.clear();
var narray = [];
var api = "https://photoslibrary.googleapis.com/v1/albums";
var headers = { "Authorization": "Bearer " + ScriptApp.getOAuthToken() };
var options = { "headers": headers, "method" : "GET", "muteHttpExceptions": true };
var param= "", nexttoken;
do {
if (nexttoken)
param = "?pageToken=" + nexttoken;
var response = UrlFetchApp.fetch(api + param, options);
var json = JSON.parse(response.getContentText());
json.albums.forEach(function (album) {
var data = [
album.title,
album.mediaItemsCount,
album.productUrl
];
narray.push(data);
});
nexttoken = json.nextPageToken;
} while (nexttoken);
albums_sh.getRange(1, 1, narray.length, narray[0].length).setValues(narray);
}
I am trying to make a Pastebin.com paste using Google Apps Script from the spreadsheet script editor. Can anyone tell me what I'm doing wrong?
function postPastebinPost() {
var options, url, apiKey, payload, response;
apiKey = <api key goes here>;
payload = 'Hello World';
options = {
'method' : 'post',
'payload' : payload
};
url = 'https://pastebin.com/api/api_post.php'
+ '?api_dev_key=' + apiKey
+ '&api_option=paste'
+ '&api_paste_code=' + encodeURIComponent(payload);
response = UrlFetchApp.fetch(url, options);
Logger.log(response);
}
I run this and my log reads Bad API request, invalid api_option. I've searched for solutions but I have not found any.
Documentation:
• Pastebin.com API
• Google Apps Script's UrlFetchApp Class
The parameters should be passed in the payload of the POST request.
function postPastebinPost() {
var apiKey = 'YOUR KEY GOES HERE';
var text = 'Hello World';
var payload = {
api_dev_key: apiKey,
api_option: 'paste',
api_paste_code: text
};
var options = {
method : 'POST',
payload: payload
};
var url = 'https://pastebin.com/api/api_post.php';
var response = UrlFetchApp.fetch(url, options);
Logger.log(response.getContentText());
}
The following is in case the user wants to create a new paste as part of their own Pastebin account (and not «Paste as a guest»). It's just an adaptation of Amit Agarwal's answer.
function postPastebinPost() {
var title = 'abc';
var contents = 'Hello World \n next line of content \n more text';
var payload = {
api_dev_key: 'aa6f3ab...', // https://pastebin.com/api#1
api_option: 'paste',
api_paste_name: title,
api_paste_code: contents,
api_paste_private: '0', // public paste
api_user_name: 'diccionario...', // name of your Pastebin account
api_user_password: 'dk398d...', // password to your Pastebin account
api_user_key: '39dk3...', // https://pastebin.com/api/api_user_key.html
};
var options = {
method : 'POST',
payload: payload
};
var url = 'https://pastebin.com/api/api_post.php';
var response = UrlFetchApp.fetch(url, options);
Logger.log(response.getContentText());
}
The whole documentation is at https://pastebin.com/api.
hello I would like to add and send as parameter on gmail settings. for all my users, and change this to make a default account to send mail.
I know hot to do with the GUI, but I wold like to do with GAS.
the code for know is jus ¿t testing for a specific user.
Reference for Gmail API
var JSON = {
"private_key": "-----BEGIN PRIVATE KEY-----\\n-----END PRIVATE KEY-----\n",
"client_email": "client..#project-id-XXXXX.gserviceaccount.com",
"client_id": "12345800",
"user_email": "mainaccount#dominio.com"
};
function getOAuthService(user) {
return OAuth2.createService('Service Account')
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(JSON.private_key)
.setIssuer(JSON.client_email)
.setSubject(JSON.user_email)
.setPropertyStore(PropertiesService.getScriptProperties())
.setParam('access_type', 'offline')
.setParam('approval_prompt', 'force')
.setScope('https://www.googleapis.com/auth/gmail.settings.sharing')
.setScope('https://www.googleapis.com/auth/gmail.settings.basic');
}
function createAlias() {
var userEmail = 'mainaccount#dominio.com';
var alias = {
alias: 'makealiasdefault#dominio.com'
};
alias = AdminDirectory.Users.Aliases.insert(alias, userEmail);
Logger.log('Created alias %s for user %s.', alias.alias, userEmail);
var service = getOAuthService();
service.reset();
if (service.hasAccess()) {
var url = 'https://www.googleapis.com/gmail/v1/users/'+userEmail+'/settings/sendAs'
var headers ={
"Authorization": 'Bearer ' + service.getAccessToken()
};
var options = {
'method':'post',
'headers': headers,
'method': 'GET',
'muteHttpExceptions': true
};
var response = UrlFetchApp.fetch(url, options);
}
Logger.log(response.getContentText());
var resource ={'sendAs':[
{'isDefault':true,
'verificationStatus':'accepted',
'sendAsEmail':alias.alias,
'treatAsAlias':true}]};
Logger.log(resource);
var sendas = Gmail.Users.Settings.SendAs.create(resource,alias.alias);
Logger.log(sendas);
}
function reset() {
var service = getOAuthService();
service.reset();
}
ANd I get an error Delegation denied for mainaccount#dominio.com
If i chagen this line var sendas = Gmail.Users.Settings.SendAs.create(resource,alias.alias);
for this
var sendas = Gmail.Users.Settings.SendAs.create(resource,userEmail);
I get a different error
Access restricted to service accounts that have been delegated domain-wide authority
The domain-wide was made follow this guide Domain-wide Delegation
Some knows how to create an send as wiht this proccess? or if something is bad with the code!
Below is a working example cleaned up from your source. A few issues with your original code:
The code seems to be trying to both make the raw UrlFetchApp.fetch HTTP call and use the Gmail library. The Gmail library is not designed to work with service accounts, it will only work against the current user which is not what you want, thus I've removed the Gmail library and I'm only using the Url Fetch.
You can only call setScope() once otherwise you overwrite the original scopes. If you have more than one scope to use, use a string with spaces between scopes.
I'm not really sure what you were trying to do with AdminDirectory, I've removed that entirely. If you want to make Admin SDK Directory API calls to create the alias email address for the user (receive mail) you'll need to add Directory scopes.
Naming your service account values to JSON is a bad idea as it overrides the JSON class of Apps Script, I've renamed the variable to service_account. Always a good idea to be specific with your variable names to avoid these kind of errors.
var service_account = {
"private_key": "-----BEGIN PRIVATE KEY...",
"client_email": "sa-email#example.com",
"client_id": "1234569343",
"user_email": "useraccount#example.com"
};
function getOAuthService(user) {
return OAuth2.createService('Service Account')
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(service_account.private_key)
.setIssuer(service_account.client_email)
.setSubject(service_account.user_email)
.setPropertyStore(PropertiesService.getScriptProperties())
.setScope('https://www.googleapis.com/auth/gmail.settings.sharing https://www.googleapis.com/auth/gmail.settings.basic')
}
function createAlias() {
var userEmail = 'useraccount#example.com';
var alias = 'myalias#example.com';
var alias_name = 'Alias User';
var service = getOAuthService();
service.reset();
if (service.hasAccess()) {
var url = 'https://www.googleapis.com/gmail/v1/users/me/settings/sendAs'
var headers ={
"Authorization": 'Bearer ' + service.getAccessToken(),
"Accept":"application/json",
"Content-Type":"application/json",
};
var resource ={
'sendAsEmail': alias,
'displayName': alias_name
};
var options = {
'headers': headers,
'method': 'POST',
'payload': JSON.stringify(resource),
'muteHttpExceptions': true
};
Logger.log(options);
var response = UrlFetchApp.fetch(url, options);
Logger.log(response.getContentText());
}
}
function reset() {
var service = getOAuthService();
service.reset();
}
'''
I have a Google Apps Script that gives me the error "Delegation denied for jasonjurotich#school.edu.mx", and is not working in order to add an alias (another email) to an account within a domain. It may be because of Token headers or some URL that is missing that authorizes something, but I cannot find enough documentation that clarifies how to add it.
This should not be confused with creating an alias in the Google Admin console for the same email. Rather, this is adding another separate account to the first account so as to send emails on behalf of the second account.
All the necessary permissions have been activated (OAuth2, a Google Service account with domain-wide delegation, necessary APIs are activated, etc.)
The script I have is the following:
var JSON = {
"private_key": "key",
"client_email": "email",
"client_id": "ID",
"user_email": "teststudent#school.edu.mx"
};
function getOAuthService(user) {
return OAuth2.createService('Service Account')
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setClientId('ID')
.setPrivateKey(JSON.private_key)
.setIssuer(JSON.client_email)
.setSubject(JSON.user_email)
.setPropertyStore(PropertiesService.getScriptProperties())
.setParam('access_type', 'offline')
.setParam('approval_prompt', 'force')
.setScope('https://www.googleapis.com/auth/script.external_request https://www.googleapis.com/auth/gmail.settings.sharing');
}
function changeEmail() {
var service = getOAuthService();
service.reset();
if (service.hasAccess()) {
var userEmail = 'teststudent#school.edu.mx';
var alias = {
sendAsEmail: 'aliastest1#school.edu.mx',
displayName: 'TS',
replyToAddress : 'aliastest1#school.edu.mx',
treatAsAlias: true
};
Gmail.Users.Settings.SendAs.create(alias, userEmail);
}
}
It seems that you are using the older version of OAuth2 library for Google Apps Script. Please check the source code and make sure it doesn't invoke ScriptApp.getProjectKey(). For example, the version below utilizes ScriptApp.getScriptId() instead of the deprecated method:
https://github.com/gsuitedevs/apps-script-oauth2/blob/master/dist/OAuth2.gs
Try connecting the new version to your GAS project as a library or manually add the files to your script and see if that fixes things.
UPDATE
I believe what happens is that you override a permissive authorization scope with a more restrictive one. Looking at the source code of the 'setScope()' method, it doesn't look like you can call it in succession.
Service_.prototype.setScope = function(scope, optSeparator) {
var separator = optSeparator || ' ';
this.params_.scope = Array.isArray(scope) ? scope.join(separator) : scope;
return this;
};
Rather, you must provide the list of scopes and the optional separator (the default one is space). As a result, the only authorization scope your script ends up using is https://www.googleapis.com/auth/gmail.settings.basic.
Bottom line: call 'setScope()' once, passing the space-separated list of required scopes.
Instead of 2 separate calls, try this:
setScope('https://www.googleapis.com/auth/gmail.settings.basic https://www.googleapis.com/auth/gmail.settings.sharing');
A colleague of mine posted something similar to this question here: Creates a custom "from" send-as alias with GAS and APIs. The following modified code is what finally worked taking into account what was put here and what they put there.
var service_account = {
"private_key": "-----BEGIN PRIVATE KEY-----",
"client_email": "changealiastest4#project-id-[].iam.gserviceaccount.com",
"client_id": "ID",
"user_email": "teststudent#school.edu.mx"
};
function getOAuthService(user) {
return OAuth2.createService('Service Account')
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setClientId('ID')
.setPrivateKey(service_account.private_key)
.setIssuer(service_account.client_email)
.setSubject(service_account.user_email)
.setPropertyStore(PropertiesService.getScriptProperties())
.setParam('access_type', 'offline')
.setParam('approval_prompt', 'force')
.setScope('https://www.googleapis.com/auth/script.external_request https://www.googleapis.com/auth/gmail.settings.sharing https://www.googleapis.com/auth/gmail.settings.basic');
}
function changeEmail() {
var userEmail = 'teststudent#school.edu.mx';
var aliasEmail = 'aliastest1#school.edu.mx';
var aliasName = 'TS';
var service = getOAuthService();
service.reset();
if (service.hasAccess()) {
var url = 'https://www.googleapis.com/gmail/v1/users/me/settings/sendAs'
var headers ={
"Authorization": 'Bearer ' + service.getAccessToken(),
"Accept":"application/json",
"Content-Type":"application/json",
};
var resource ={
sendAsEmail: aliasEmail,
displayName: aliasName,
replyToAddress : aliasEmail,
treatAsAlias: true,
verificationStatus: 'accepted'
};
var options = {
'headers': headers,
'method': 'POST',
'payload': JSON.stringify(resource),
'muteHttpExceptions': true
};
Logger.log(options);
var response = UrlFetchApp.fetch(url, options);
Logger.log(response.getContentText());
}
}