As a test case, I'm trying to copy a file from Google Drive to Dropbox using Google Scripts
function pushBuild() {
// Setup OAuthServiceConfig
var oAuthConfig = UrlFetchApp.addOAuthService("dropbox");
oAuthConfig.setAccessTokenUrl("https://api.dropbox.com/1/oauth/access_token");
oAuthConfig.setRequestTokenUrl("https://api.dropbox.com/1/oauth/request_token");
oAuthConfig.setAuthorizationUrl("https://www.dropbox.com/1/oauth/authorize");
oAuthConfig.setConsumerKey(ScriptProperties.getProperty("dropboxKey"));
oAuthConfig.setConsumerSecret(ScriptProperties.getProperty("dropboxSecret"));
var fileName = "blah.zip"
var folderName = "upload_dir"
var docs = DocsList.getFolder(folderName).find(fileName);
for(n=0;n<docs.length;++n){
if(docs[n].getName() == fileName){
var ID = docs[n].getId();
var options = {
"oAuthServiceName" : "dropbox",
"oAuthUseToken" : "always",
"method" : "put",
"payload" : docs[n].getBlob().getBytes(),
"contentType" : "application/zip"
};
var response = UrlFetchApp.fetch("https://api-content.dropbox.com/1/files_put/sandbox/upload_dir/" + fileName, options);
Logger.log(response);
}
}
}
The authorization request for the application in Dropbox appears and it tells me that I've successfully authorized my app, but when I check, the app is not in the list of "My Apps", the file has not been uploaded and there are no entries in the log. The directory "upload_dir" exists on both GD and DB. I've tried the same code with "App Folder" and "Full Dropbox" app types, but get the same result.
Additionally, running the script again once again triggers the Authorization page, similar to
to appear, clicking "Allow" then shows the success screen but the application is not listed in "My Apps". Running the script again repeats the process.
Can anyone point out what I've done wrong?
Update
So, I've now tried to implement this using the individual api calls and am still not having any success.
function testOAuth() {
var timestamp = getTimestamp();
var nonce = getNonce(timestamp);
var authString = 'OAuth oauth_version="1.0", oauth_signature_method="PLAINTEXT", oauth_signature="' + encodeURIComponent(ScriptProperties.getProperty("dropboxSecret") + '&') + '", oauth_consumer_key="' + ScriptProperties.getProperty("dropboxKey") + '"';
Logger.log(authString)
var options = {
method : "POST",
headers : {"Authorization" : authString}
}
var response = UrlFetchApp.fetch("https://api.dropbox.com/1/oauth/request_token",options);
var params = response.getContentText().split("&");
var map = new Map;
for(i = 0; i < params.length; i++){
var param = params[i].split("=");
map.put(param[0],param[1]);
}
var authStringx = "https://www.dropbox.com/1/oauth/authorize?oauth_token=" + map.get("oauth_token");
Logger.log(authStringx);
var response2 = UrlFetchApp.fetch(authStringx);
Logger.log(response2.getContentText());
var authString2 = 'OAuth oauth_version="1.0", oauth_signature_method="PLAINTEXT", oauth_token="' + map.get("oauth_token") + '" , oauth_signature="' + encodeURIComponent(ScriptProperties.getProperty("dropboxSecret") + '&' + map.get("oauth_token_secret")) + '", oauth_consumer_key="' + ScriptProperties.getProperty("dropboxKey") + '",oauth_timestamp="'+ timestamp +'", oauth_nonce="' + nonce +'"';
Logger.log(authString2);
var options3 = {
"method" : "POST",
"Authorization" : authString2
}
var response3 = UrlFetchApp.fetch("https://api.dropbox.com/1/oauth/access_token", options3);
Logger.log(response3.getContentText());
}
var getTimestamp = function(){
return (Math.floor((new Date()).getTime() / 1000)).toString()
}
var getNonce = function(timestamp){
return timestamp + Math.floor( Math.random() * 100000000)
}
The code implementation for the map is here. The main problem that I can see is that authorize step does not invoke the Dropbox authorize end point (ie no browser redirection takes place to authorize the application). If I place a breakpoint just after the line Logger.log(authStringx); and manually visit the web page pasting in the contents of authStringx I get the screen to authorize my app. I accept that and get the message that the app is registered in "My Apps". I now let the program continue and I am greeted with the message
Any ideas?
Pram,
I was trying to accomplish the same task and came across your post. I am not a programmer, so I can't figure out the second part either (launching the authorization page fails), but I was able to complete the process in the third step and connect my app successfully.
Instead of:
var authString2 = 'OAuth oauth_version="1.0", oauth_signature_method="PLAINTEXT", oauth_token="' + map.get("oauth_token") + '" , oauth_signature="' + encodeURIComponent(ScriptProperties.getProperty("dropboxSecret") + '&' + map.get("oauth_token_secret")) + '", oauth_consumer_key="' + ScriptProperties.getProperty("dropboxKey") + '",oauth_timestamp="'+ timestamp +'", oauth_nonce="' + nonce +'"';
Logger.log(authString2);
var options3 = {
"method" : "POST",
"Authorization" : authString2
}
var response3 = UrlFetchApp.fetch("https://api.dropbox.com/1/oauth/access_token", options3);
Logger.log(response3.getContentText());
I used:
var authtokenURL = "https://api.dropbox.com/1/oauth/access_token";
var authString2 = "?oauth_signature_method=PLAINTEXT&oauth_token=" + [MY_OAUTH_REQUEST_TOKEN] + "&oauth_signature=" + encodeURIComponent([MY_DROPBOX_CONSUMER_SECRET] + "&" + [MY_OAUTH_REQUEST_SECRET]) +"&oauth_consumer_key=" + [MY_DROPBOX_CONSUMER_KEY];
Logger.log(authString2);
var response3 = UrlFetchApp.fetch("https://api.dropbox.com/1/oauth/access_token" + authString2);
Logger.log(response3.getContentText());
I then got an email confirmation that I connected a new app to Dropbox, and my app does show up under Settings in my account. Anyway, as I said, I'm no programmer, so sorry for the ugly code. Thanks for supplying your code for me to make it this far. I hope this helps you at least move forward, even if it doesn't solve the underlying problem.
I am able to see this issue as well. There is something special going on here with Dropbox. You should check on their forums or with their API support team. Looks like they are not correctly accepting callback params. Perhaps this is a development mode limitation (vs. production mode). Or perhaps they are stringent about some POST vs GET differences that Google doesn't support.
This code below exhibits the same issue you described where the authorization is never complete.
function dropbox() {
var oAuthCfg = UrlFetchApp.addOAuthService("dropbox");
oAuthCfg.setAccessTokenUrl('https://api.dropbox.com/1/oauth/access_token');
oAuthCfg.setRequestTokenUrl('https://api.dropbox.com/1/oauth/request_token');
oAuthCfg.setAuthorizationUrl('https://api.dropbox.com/1/oauth/authorize');
oAuthCfg.setConsumerKey('DROPBOX_KEY');
oAuthCfg.setConsumerSecret('DROPBOX_SECRET');
var options = {oAuthServiceName:'dropbox',oAuthUseToken:'always'}
var url = 'https://api.dropbox.com/1/account/info';
var response = UrlFetchApp.fetch(url, options).getContentText();
Logger.log(response);
}
However, the same code works without issue with the Twitter OAuth 1 API. The code below should dump out JSON from your stream (once you substitute the tokens from your setup in http://dev.twitter.com
function twitter(){
var oAuthCfg = UrlFetchApp.addOAuthService('twitter');
oAuthCfg.setAccessTokenUrl('http://api.twitter.com/oauth/access_token');
oAuthCfg.setRequestTokenUrl('http://api.twitter.com/oauth/request_token');
oAuthCfg.setAuthorizationUrl('http://api.twitter.com/oauth/authorize');
oAuthCfg.setConsumerKey('TWITTER_KEY');
oAuthCfg.setConsumerSecret('TWITTER_SECRET');
var options = {oAuthServiceName:'twitter',oAuthUseToken:'always'}
var url = "http://api.twitter.com/1/statuses/user_timeline.json";
var response = UrlFetchApp.fetch(url, options).getContentText();
Logger.log(response);
}
If you are able to narrow this down to a Google issue log a bug here on the Issue Tracker.
Related
On my website, I am hosting a few videos via Google Drive. On my sidebar, there is a thumbnail of the videos and I'd like to show the duration of the video in the corner. I have looked at two similar questions (here and here) to solve this problem. This is what I produced from looking at these two problems:
function sample1() {
console.log("running script");
var fileId = "theFileID"; // Please set the file ID of the video file.
var fields = "mimeType,name,videoMediaMetadata"; // duration is included in "videoMediaMetadata"
var url = "https://www.googleapis.com/drive/v3/files/" + fileId + "?fields=" + encodeURIComponent(fields) + "&access_token=" + ScriptApp.getOAuthToken();
var res = UrlFetchApp.fetch(url, {headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}});
var obj = JSON.parse(res);
console.log("filename: %s, duration: %s seconds", obj.name, obj.videoMediaMetadata.durationMillis / 1000);
}
sample1();
However, when I check the console after running this script, nothing is printed after "running script". Is there a different approach I should be taking in my program when attempting to solve this problem via Google APIs?
Using the Drive API method Files: get with Apps Script I have been able to get the durationMillis from the video.
You have to add the Drive API Advanced Services on the Apps Script project:
function getVideoLength() {
var fileId = "FILE ID";
var returnedFile = Drive.Files.get(fileId);
Logger.log(returnedFile.videoMediaMetadata.durationMillis)
}
I wan't to Embed google spreadsheets without publishing, this file set only me access.
I try like this :
function viewSheet(idSheet){
var ss = SpreadsheetApp.openById(idSheet);
var idSheet2 = ss.getSheetByName("Sheet2").getSheetId();
var url = "https://docs.google.com/spreadsheets/d/" + idSheet + "/pubhtml#gid=" + idSheet2;
return url ;
}
i don't wan't like this.
i wan't like this, this is i use publish in menu: "FILE -> Publish to the web" and i have URL not use code above !
P/s: Sorry my english is a bit poor, please guide me fix it !!!
How to publish to the Web with Apps Script
Your code attempts to retrieve the link to the published to the web version of the spreadsheet
However, before using this link, you need to enable the publishing first
This can be done with specifying the respective parameters of Drive revisions
Once you enabled publishing you can retrieve the link as you did before, however you should change the URL from
var url = "https://docs.google.com/spreadsheets/d/" + idSheet + "/pubhtml#gid=" + idSheet2;
to
var url = "https://docs.google.com/spreadsheet/pubhtml?key=" + idSheet + "&gid=" + idSheet2 + "&single=true";
Sample:
function viewSheet(idSheet){
var revisionsList = Drive.Revisions.list(idSheet);
var revisions = revisionsList.items;
var revisionId =revisions[revisions.length-1].id;
var lastRevision = Drive.Revisions.get(idSheet, revisionId);
lastRevision.published = true;
lastRevision.publishAuto = true;
lastRevision.publishedOutsideDomain = true;
Drive.Revisions.update(lastRevision, idSheet, revisionId);
var ss = SpreadsheetApp.openById(idSheet);
var idSheet2 = ss.getSheetByName("Sheet2").getSheetId();
var url = "https://docs.google.com/spreadsheet/pubhtml?key=" + idSheet + "&gid=" + idSheet2 + "&single=true";
return url ;
}
Be aware that for accessing Drive revisions you need to enable the advanced service Drive
I am working in a Google Apps Script web app using Contacts API v3, to access all user's contacts within the domain.
I have no problems so far with Contacts API requests, but I have no idea yet on how to get authorization across the domain to access any user's contacts (other than me).
I have tried OAuth domain key from cpanel - advanced tools, with no results so far. I got "Request failed for returned code 403 (Forbidden)" when trying with other users within the domain
Thanks in advance, Fausto
EDIT-1 (Mar.05) I'm closer now, but need a bit of help
I have combined 2LO (2-legged OAuth) with oauth_signature and signing request, but still getting Error 401 (Client Error)!!1. This is the sample code I am working with now.
function test_xOAuth() {
// OAUTH_CONSUMER_SECRET from GApps: control panel > advanced tools > Manage OAuth domain key
var domain = Session.getEffectiveUser().getEmail().split("#")[1];
var xuser = 'fausto#thexs.ca';
var method = "GET";
var baseUrl = "https://www.google.com/m8/feeds/groups/default/full";
var timestamp = getTimestamp();
var paramsJson = {
oauth_consumer_key : domain,
oauth_nonce : getNonce(timestamp),
oauth_signature_method : "HMAC-SHA1",
oauth_timestamp : timestamp,
oauth_version : "1.0"
};
var paramsStringArray = [];
for (var k in paramsJson) paramsStringArray.push(k + '="' + paramsJson[k] + '"');
var paramsString = paramsStringArray.join("&") + '&xoauth_requestor_id=' + xuser;
var signatureBaseString = method +"&"+ encodeURIComponent(baseUrl) +"&"+ encodeURIComponent(paramsString);
var signatureBytes = Utilities.computeHmacSha256Signature(signatureBaseString, OAUTH_CONSUMER_SECRET);
var signature = Utilities.base64Encode(signatureBytes);
var xoauthString = 'OAuth ' + paramsStringArray.join(",") + ',oauth_signature="' + signature + '"';
var options = {
method : method,
headers : {"Authorization" : xoauthString}
}
var url = baseUrl + '?xoauth_requestor_id=' + 'fausto#thexs.ca';
var response = UrlFetchApp.fetch(url, options);
var responseHeader = response.getHeaders();
var responseText = response.getContentText();
return HtmlService.createHtmlOutput(responseText);
}
var getTimestamp = function(){
return (Math.floor((new Date()).getTime() / 1000)).toString()
}
var getNonce = function(timestamp){
return timestamp + Math.floor( Math.random() * 100000000)
}
Thanks in advance for any help !! Fausto
First, you should properly URL-encode all parameters before you calculate signature.
Second, strip the quotes, you don't really need them, especially in the base string.
Third, you should use signature method you're specifying i.e. HMAC-SHA1. And last but not least, despite you're not using OAuth token you still need to include '&' in the encryption key.
Here's the code that works properly:
var OAUTH_CONSUMER_SECRET = 'you secret goes here';
var domain = 'domain.tld';
var username = 'test.user';
var xuser = encodeURIComponent(username+'#'+domain);
var method = "GET";
var baseUrl = "https://www.google.com/m8/feeds/groups/default/full";
var timestamp = Math.round(new Date().getTime() / 1000);
var paramsJson = {
oauth_consumer_key : domain,
oauth_nonce : timestamp,
oauth_signature_method : "HMAC-SHA1",
oauth_timestamp : timestamp,
oauth_version : "1.0"
};
var paramsStringArray = [];
for (var k in paramsJson) paramsStringArray.push(k + '=' + encodeURIComponent(paramsJson[k]));
var paramsString = paramsStringArray.join("&") + "&xoauth_requestor_id="+xuser;
var signatureBaseString = method +"&"+ encodeURIComponent(baseUrl) +"&"+ encodeURIComponent(paramsString);
var signatureBytes = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_1, signatureBaseString, OAUTH_CONSUMER_SECRET+'&');
var signature = encodeURIComponent(Utilities.base64Encode(signatureBytes));
var xoauthString = 'OAuth ' + paramsStringArray.join(", ") + ', oauth_signature="' + signature + '"';
var options = {
method : method,
headers : {authorization: xoauthString}
}
var url = baseUrl + '?xoauth_requestor_id=' + xuser;
var response = UrlFetchApp.fetch(url, options);
I have not performed the access to contacts like you mention here but I have manage to perform a similar action to act as a domain user and access the users Google drive, The one limiting factor to this was that to be able to do what you are trying to do is that you have to be a super administrator for you Google domain and the access level i had to use was trough URL Requests and REST API, You might also what to have a look at Google Domain Shared Contacts API to be able to manage your shared contacts in a Google domain and leave everyone's personal contacts to be managed by them self
I had a wild idea that I could build a website blog for an unsophisticated user friend using Google Drive Documents to back it. I was able to create a contentService that compiles a list of documents. However, I can't see a way to convert the document to HTML. I know that Google can render documents in a web page, so I wondered if it was possible to get a rendered version for use in my content service.
Is this possible?
You can try this code :
function getGoogleDocumentAsHTML(){
var id = DocumentApp.getActiveDocument().getId() ;
var forDriveScope = DriveApp.getStorageUsed(); //needed to get Drive Scope requested
var url = "https://docs.google.com/feeds/download/documents/export/Export?id="+id+"&exportFormat=html";
var param = {
method : "get",
headers : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
muteHttpExceptions:true,
};
var html = UrlFetchApp.fetch(url,param).getContentText();
Logger.log(html);
}
Node.js Solution
Using the Google APIs Node.js Client
Here's how you can get a google doc as html using google drive's node.js client library.
// import googleapis npm package
var google = require('googleapis');
// variables
var fileId = '<google drive doc file id>',
accessToken = '<oauth access token>';
// oauth setup
var OAuth2 = google.auth.OAuth2,
OAuth2Client = new OAuth2();
// set oauth credentials
OAuth2Client.setCredentials({access_token: accessToken});
// google drive setup
var drive = google.drive({version: 'v3', auth: OAuth2Client});
// download file as text/html
var buffers = [];
drive.files.export(
{
fileId: fileId,
mimeType: 'text/html'
}
)
.on('error', function(err) {
// handle error
})
.on('data', function(data) {
buffers.push(data); // data is a buffer
})
.on('end', function() {
var buffer = Buffer.concat(buffers),
googleDocAsHtml = buffer.toString();
console.log(googleDocAsHtml);
});
Take a look at the Google Drive V3 download docs for more languages and options.
Google docs currently has a function to do this.
Just download to zip(.html) and you can have a zip archive with html & image (if inserted)
I know this is not solution based on code, but its working :)
There is no direct method in GAS to get an HTML version of a doc and this is quite an old enhancement request but the workaround described originally by Henrique Abreu works pretty well, I use it all the time...
The only annoying thing in the authorization process that needs to be called from the script editor which makes it uneasy to use in a shared application (with "script unable" users) but this only happens once ;).
There is also a Library created by Romain Vialard that makes things (a bit) easier... and adds a few other interesting functions.
Here is a little snipped for the new version of goole AOuth following the idea posted by Enrique:
function exportAsHTML(){
var forDriveScope = DriveApp.getStorageUsed(); //needed to get Drive Scope requested
var docID = DocumentApp.getActiveDocument().getId();
var url = "https://docs.google.com/feeds/download/documents/export/Export?id="+docID+"&exportFormat=html";
var param = {
method : "get",
headers : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
muteHttpExceptions:true,
};
var html = UrlFetchApp.fetch(url,param).getContentText();
return html;
}
and then use the usual mailApp:
function mailer(){
var docbody = exportAsHTML();
MailApp.sendEmail({
to: "email#mail.com",
subject: "document emailer",
htmlBody: docbody });
}
Hope the new workaround helps
JD
You may use the solution here
/**
* Converts a file to HTML. The Advanced Drive service must be enabled to use
* this function.
*/
function convertToHtml(fileId) {
var file = Drive.Files.get(fileId);
var htmlExportLink = file.exportLinks['text/html'];
if (!htmlExportLink) {
throw 'File cannot be converted to HTML.';
}
var oAuthToken = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(htmlExportLink, {
headers:{
'Authorization': 'Bearer ' + oAuthToken
},
muteHttpExceptions: true
});
if (!response.getResponseCode() == 200) {
throw 'Error converting to HTML: ' + response.getContentText();
}
return response.getContentText();
}
Pass as fileId, the id of the google doc and to enable advanced drive services follow the instructions here.
I've had this problem as well. The HTML that the Document HTML Export spits out is really ugly, so this was my solution:
/**
* Takes in a Google Doc ID, gets that doc in HTML format, cleans up the markup, and returns the resulting HTML string.
*
* #param {string} the id of the google doc
* #param {boolean} [useCaching] enable or disable caching. default true.
* #return {string} the doc's body in html format
*/
function getContent(id, useCaching) {
if (!id) {
throw "Please call this API with a valid Google Doc ID";
}
if (useCaching == null) {
useCaching = true;
}
if (typeof useCaching != "boolean") {
throw "If you're going to specify useCaching, it must be boolean.";
}
var cache = CacheService.getScriptCache();
var cached = cache.get(id); // see if we have a cached version of our parsed html
if (cached && useCaching) {
var html = cached;
Logger.log("Pulling doc html from cache...");
} else {
Logger.log("Grabbing and parsing fresh html from the doc...");
try {
var doc = DriveApp.getFileById(id);
} catch (err) {
throw "Please call this API with a valid Google Doc ID. " + err.message;
}
var docName = doc.getName();
var forDriveScope = DriveApp.getStorageUsed(); // needed to get Drive Scope requested in ScriptApp.getOAuthToken();
var url = "https://docs.google.com/feeds/download/documents/export/Export?id=" + id + "&exportFormat=html";
var param = {
method: "get",
headers: {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
muteHttpExceptions:true,
};
var html = UrlFetchApp.fetch(url, param).getContentText();
// nuke the whole head section, including the stylesheet and meta tag
html = html.replace(/<head>.*<\/head>/, '');
// remove almost all html attributes
html = html.replace(/ (id|class|style|start|colspan|rowspan)="[^"]*"/g, '');
// remove all of the spans, as well as the outer html and body
html = html.replace(/<(span|\/span|body|\/body|html|\/html)>/g, '');
// clearly the superior way of denoting line breaks
html = html.replace(/<br>/g, '<br />');
cache.put(id, html, 900) // cache doc contents for 15 minutes, in case we get a lot of requests
}
Logger.log(html);
return html;
}
https://gist.github.com/leoherzog/cc229d14a89e6327336177bb07ac2980
Perhaps this would work for you...
function doGet() {
var blob = DriveApp.getFileById('myFileId').getAsHTML();
return HtmlService.createHtmlOutput(blob);
}
This question already has answers here:
Google app scripts: email a spreadsheet as excel
(2 answers)
Closed 2 years ago.
I would like to write an apps script to email an excel version of my Google Spreadsheet. I know I can save the spreadsheet as an Excel file. I am not sure if I can use the script to email the excel version out as an attachment. How can this be done?
After an answer on another recent post (Thomas van Latum), I tried the suggested doc api and get an interesting result... here is the test code I used and that is working nicely except the file is in xlsx format, not in xls but this is not necessarily an issue these days :
function googleOAuth_(name,scope) {
var oAuthConfig = UrlFetchApp.addOAuthService(name);
oAuthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope="+scope);
oAuthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
oAuthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
oAuthConfig.setConsumerKey('anonymous');
oAuthConfig.setConsumerSecret('anonymous');
return {oAuthServiceName:name, oAuthUseToken:"always"};
}
function test(){
var id = 'spreadsheet_ID'
var url = 'https://docs.google.com/feeds/';
var doc = UrlFetchApp.fetch(url+'download/spreadsheets/Export?key='+id+'&exportFormat=xls',
googleOAuth_('docs',url)).getBlob()
DocsList.createFile(doc).rename('newfile.xls')
}
note : if you don't rename it, its default name is Export.xlsx , it might be more usefull to get its ID to use it later...
so the last line could be like this instead :
var xlsfileID = DocsList.createFile(doc).getId()
EDIT : to trigger the authorization process, try a small function like this, run it from the script editor
function autorise(){
// function to call to authorize googleOauth
var id=SpreadsheetApp.getActiveSpreadsheet().getId();
var url = 'https://docs.google.com/feeds/';
var doc = UrlFetchApp.fetch(url+'download/documents/Export?exportFormat=html&format=html&id='+id,
googleOAuth_('docs',url)).getContentText();
}
As I spent about four hours of playing Rumpelstiltskin because none of the typically very old code snippets for the old Spreadsheet versions and the old OAUTH you can find when googling "google docs script send excel attachment" or similar (i.e. you want to take an existing Spreadsheet, convert it to Excel format and send it as email attachment) actually worked, I finally found the solution.
To create the actual attachment content, neither the supposed res.getContent() nor res.getBlob() nor res.getBytes alone worked. These hints are misleading!
The only thing that works for me is response.getBlob().getContent()!
Whole code :
function sendCurrentDocAsEmail() {
var driveService = getDriveService();
var ssID = SpreadsheetApp.getActiveSpreadsheet().getId();
var sheetName = SpreadsheetApp.getActiveSpreadsheet().getName();
var email = "recipient#demo.com"
var subject = "Here be Subjects";
var body = "Don't even think about learning how to code. It's wasted time.";
var file = Drive.Files.get(ssID );
var url = file.exportLinks[MimeType.MICROSOFT_EXCEL];
var response = UrlFetchApp.fetch(url, {
headers: {
Authorization: 'Bearer ' + driveService.getAccessToken()
}
});
var attachments = [{
fileName:sheetName+".xlsx",
content: response.getBlob().getBytes(), // this single line has cost me hours!
mimeType:"application//xls",
headers: {
Authorization: 'Bearer ' + driveService.getAccessToken()
}
}];
MailApp.sendEmail(email,subject ,body, {attachments:attachments});
}
Where getDriveService() is a function from Google's "OAuth2 for Apps Script" readme on https://github.com/googlesamples/apps-script-oauth2
The latest working version is below. Based on this example, i.e. similar as in previous answer but uses Google Service Account which does not require a human going by link to receive a token. You have to install Oath library from Google, the instructions are pretty clear.
var PRIVATE_KEY = 'xxx'
var CLIENT_EMAIL = 'xxx';
var USER_EMAIL=Session.getActiveUser().getEmail()
function getOathService() {
return OAuth2.createService('GoogleDrive:' + USER_EMAIL)
// Set the endpoint URL.
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the private key and issuer.
.setPrivateKey(PRIVATE_KEY)
.setIssuer(CLIENT_EMAIL)
// Set the name of the user to impersonate. This will only work for
// Google Apps for Work/EDU accounts whose admin has setup domain-wide
// delegation:
// https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
.setSubject(USER_EMAIL)
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scope. This must match one of the scopes configured during the
// setup of domain-wide delegation.
.setScope('https://www.googleapis.com/auth/drive');
}
function sendEmail() {
var oathService = getOathService();
var ssID = SpreadsheetApp.getActiveSpreadsheet().getId();
var file = Drive.Files.get(ssID );
var url = file.exportLinks[MimeType.MICROSOFT_EXCEL];
var file = UrlFetchApp.fetch(url, {
headers: {
Authorization: 'Bearer ' + oathService.getAccessToken()
}
});
var attachments = [{
fileName:'xxx.xls',//TODO DATE
content: file.getBlob().getBytes(),
mimeType:"application//xls",
headers: {
Authorization: 'Bearer ' + oathService.getAccessToken()
}
}];
MailApp.sendEmail('email#domain.com', 'xxx', 'Hi,\n\nPlease see the last data in attachment',{attachments:attachments});
}
The one that worked for me:
var AUTH_TOKEN = "Enter your OAuth_Token";
ssID = SpreadsheetApp.getActiveSpreadsheet().getId();
var url = "http://spreadsheets.google.com/feeds/download/spreadsheets/Export?key="+ ssID + "&exportFormat=xls";
//Add &gid=x at the end of above url if you only want a particular sheet
var auth = "AuthSub token=\"" + AUTH_TOKEN + "\"";
var res = UrlFetchApp.fetch(url, {headers: {Authorization: auth}});
var attachments = [{fileName:"<Filename>.xls", content: res.getContent(),mimeType:"application/vnd.ms-excel"}];
MailApp.sendEmail("<recipient's email id>", "<email subject>", "<email body>", {attachments: attachments});
Get OAuth documentation & you token from here https://developers.google.com/accounts/docs/OAuth2
Use the following snippet of code after modifying it to suit your needs
var file = DocsList.getFileById(FILE_ID);
var attachment = file.getAs('application/vnd.ms-excel');
MailApp.sendEmail("abcd#example.com", "Subject", " Body" , {"fileName": "Your_file_name" , "mimeType" : "application/vnd.ms-excel" , "content":attachment.getBytes() } );
Note that this code is not tested, so please feel free to fix an error or two that might pop up