We implemented a function to create drafts using Compose Actions.
However, the subject is garbled.
If the subject is あいうえお, it will be Re: BDFHJ.
I want to prevent garbled characters.
this code.
Code.js
function buildCard (e) {
var card = CardService.newCardBuilder();
card.setHeader(CardService.newCardHeader().setTitle("タイトル"));
var section = CardService.newCardSection();
var composeAction = CardService.newAction()
.setFunctionName('createReplyDraft');
var composeButton = CardService.newTextButton()
.setText('Compose Reply')
.setComposeAction(composeAction, CardService.ComposedEmailType.REPLY_AS_DRAFT);
section.addWidget(composeButton);
card.addSection(section);
return card.build();
}
/**
* Creates a draft email (with an attachment and inline image)
* as a reply to an existing message.
* #param {Object} e data passed by the compose action.
* #return {ComposeActionResponse}
*/
function createReplyDraft(e) {
// Activate temporary Gmail add-on scopes, in this case to allow
// a reply to be drafted.
var accessToken = e.messageMetadata.accessToken;
GmailApp.setCurrentMessageAccessToken(accessToken);
// Creates a draft reply.
var messageId = e.messageMetadata.messageId;
var message = GmailApp.getMessageById(messageId);
var draft = message.createDraftReply('あいうえお'); //There is no problem with body.
// Return a built draft response. This causes Gmail to present a
// compose window to the user, pre-filled with the content specified
// above.
return CardService.newComposeActionResponseBuilder()
.setGmailDraft(draft).build();
}
appsscript.json
{
"oauthScopes": [
"https://www.googleapis.com/auth/gmail.addons.execute",
"https://www.googleapis.com/auth/gmail.readonly"
],
"gmail": {
"name": "Gmail Add-on Quickstart",
"logoUrl": "https://www.gstatic.com/images/icons/material/system/2x/bookmark_black_24dp.png",
"contextualTriggers": [{
"unconditional": {
},
"onTriggerFunction": "buildCard"
}],
"openLinkUrlPrefixes": [
"https://mail.google.com/"
],
"primaryColor": "#4285F4",
"secondaryColor": "#4285F4"
},
"oauthScopes":[
"https://mail.google.com/",
"https://www.googleapis.com/auth/gmail.addons.execute",
"https://www.googleapis.com/auth/script.external_request"]
}
this flow.
step1.
You've got mail.
step2.
Click the Compose Reply
step3.
Edit Subject.
step4.
Subject is garbled.
Related
I have a problem with Apps Script and sending email. I'm using a Google Form and a Google Sheet to collect data. When the survey is send, I linked the main function to a trigger so the main perform some calculation and generate a PDF. At the end of the main, a function for sending an email is called, but I have an error. I also added Gmail API. I tried to add more link into oauthScopes in my appsscript.json, but I had the same result.
This is my appsscript.json:
{
"oauthScopes": [
"https://www.googleapis.com/auth/gmail.send",
"https://www.googleapis.com/auth/gmail.compose",
"https://www.googleapis.com/auth/gmail.modify"
],
"timeZone": "America/Toronto",
"dependencies": {
"enabledAdvancedServices": [
{
"userSymbol": "Gmail",
"version": "v1",
"serviceId": "gmail"
}
]
},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8"
}
This is my function that's called by my main:
function sendEmail(email, pdfFile){
var subject = "Test";
var message = "Hi";
GmailApp.sendEmail(email, subject, message);
}
When this function is call, I have the following problem:
Exception: The script does not have permission to perform that action. Required permissions: (https://www.googleapis.com/auth/gmail.send || https://www.googleapis.com/auth/gmail.compose || https://www.googleapis.com/auth/gmail.modify || https://mail.google.com/ || https://www.googleapis.com/auth/gmail.addons.current.action.compose)
How can I solve this problem ?
Try:
function sendEmail(email, pdfFile){
var subject = "Test";
var message = "Hi";
GmailApp.sendEmail(email, subject, message, {attachments:[pdfFile]});
}
I am trying to create a Google app that will search a keyword in a Google Sheets, request (Column A) and return the response (Column B). The script's working well, but whenever the app is called by an end user it is requesting permission to access the Sheets.
I want to know how end users can access the app without permission and how can I provide the app to use service account to read the spreadsheet within the code?
function ReadExcelFile()
{
var spreadsheetId = <MySpreadSheetID>;
var sheet = SpreadsheetApp.openById(spreadsheetId);
var SearchText='Hello';
var data = sheet.getRange('A:B').getValues();
for(var i in data){
if(i>0){
var row = data[i][0];
Logger.log('Searching for a KeyWord: '+SearchText+' From the SpreetSheet Value : '+row);
var SearchCount=SearchText.indexOf(row);
if(SearchCount>-1){
var row2=data[i][1];
Logger.log(SearchCount+' '+row2);
break;
}
}
}
}
Request | Response
Hello | Hi Welcome!!
Hey | Hey Welcome!!
Output would be..
Hi Welcome!!
I also faced this problem, I want to read the container bound spreadsheet data and reply back as messages to the end user when they messages to the google chatbot, Finally I solved by this way, it may help.
Here is my appscript.json code
{
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"dependencies": {
"libraries": [
{
"userSymbol": "OAuth2",
"libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF",
"version": "26"
}
],
"enabledAdvancedServices": [
{
"userSymbol": "Sheets",
"version": "v4",
"serviceId": "sheets"
}
]
},
"chat": {
"addToSpaceFallbackMessage": "Thank you for adding me"
}
}
and here is the oauth, token access, and query api code
var PRIVATE_KEY = 'your service account private key generated Google Cloud Project (GCP) console ';
var CLIENT_EMAIL = 'clien-email';
var ssId = 'Spreadsheet Id which you want to read or write data from end user';
/**
* Configures the Chatbot service.
*/
function getChatbotService() {
return OAuth2.createService("sathibhai-bot")
// 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 property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scope.
.setScope("https://www.googleapis.com/auth/chat.bot");
}
/**
* Configures the spreadsheet service.
*/
function getSpreasheetService() {
return OAuth2.createService("spreadsheet")
// 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 property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scope.
.setScope("https://www.googleapis.com/auth/spreadsheets");
}
function readSheet(){
var service = getSpreasheetService();
var range = 'Sheet1!A1:D';
var url = 'https://sheets.googleapis.com/v4/spreadsheets/' + ssId +'/values/' + range;
var response = UrlFetchApp.fetch(url, { headers: {Authorization: 'Bearer ' + service.getAccessToken() } });
var rep = JSON.parse(response.getContentText());
var values = rep.values;
for(row in values)
Logger.log(values[row][0] + ":" + values[row][1] + ":" + values[row][2] + ":" + values[row][3]); //you can use these data as your requirements
}
Note that:
Share your spreadsheet with the service account i.i your-service-account#sys-..............iam.gserviceaccount.com (and no need to share to any body except service account)
Enable Spreadsheet API in GCP console.
I tried to get some data from google sheet and display it in Gmail addons.
When i tried to run getValue() function i am getting error like below.
You do not have permission to call openById (line 29, file "Code")Dismiss
This is my code.gs file code
function createWidgetCard() {
return CardService
.newCardBuilder()
.setHeader(
CardService.newCardHeader()
.setTitle('Widget demonstration')
.setSubtitle('Check out these widgets')
.setImageStyle(CardService.ImageStyle.SQUARE)
.setImageUrl(
'https://www.example.com/images/headerImage.png'))
.addSection(
CardService.newCardSection()
.setHeader('Simple widgets') // optional
.addWidget(CardService.newTextParagraph().setText(
'These widgets are display-only. ' +
'A text paragraph can have multiple lines and ' +
getValue()))
.addWidget(CardService.newImage().setImageUrl(
'https://www.example.com/images/mapsImage.png')))
.addCardAction(CardService.newCardAction().setText('Gmail').setOpenLink(
CardService.newOpenLink().setUrl('https://mail.google.com/mail')))
.build();
}
//get data from sheet
function getValue(){
var ss = SpreadsheetApp.openById("181tnith14lu8ttAvtqsU3gHi32-UjcrPqH5Pjuenk5A");
var sheet = ss.getSheets()[0];
var lastRaw = sheet.getLastRow();
var text = sheet.getRange(lastRaw, 3.0).getValue();
Logger.log("text");
return text;
}
This is my manifest file code(appscript.json)
{
"oauthScopes": [
"https://www.googleapis.com/auth/gmail.addons.execute",
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/script.storage",
"https://www.googleapis.com/auth/script.external_request"
],
"gmail": {
"name": "Finetech Addon",
"logoUrl": "https://www.gstatic.com/images/icons/material/system/2x/bookmark_black_24dp.png",
"contextualTriggers": [{
"unconditional": {
},
"onTriggerFunction": "createWidgetCard"
}],
"openLinkUrlPrefixes": [
"https://mail.google.com/"
],
"primaryColor": "#4285F4",
"secondaryColor": "#4285F4",
"version": "TRUSTED_TESTER_V2"
}
}
My requirement is accessing sheet and get some data and display it on Gmail addon. It could be very helpful if anyone can provide correct code snipes.
I think that the scope for using Spreadsheet is required to be added to "oauthScopes" of manifests. So please add https://www.googleapis.com/auth/spreadsheets to "oauthScopes" in appsscript.json. And try again.
If this didn't work, I'm sorry.
I have create simple gmail addon using google script,in that i have struggle here,
how to get textinput value when we perform some action,i have checked the document, i couldn't find any methods
TextInput
The below code i have tried,
var card = CardService.newCardBuilder();
card.setHeader(CardService.newCardHeader().setTitle("Login Here"));
var section = CardService.newCardSection()
var cleint_id_Input = CardService.newTextInput()
.setFieldName("client_id")
.setTitle("Please enter clinet id")
var username_Input = CardService.newTextInput()
.setFieldName("username")
.setTitle("Please enter username")
var password_Input = CardService.newTextInput()
.setFieldName("password")
.setTitle("Please enter password")
section.addWidget(cleint_id_Input)
section.addWidget(username_Input)
section.addWidget(password_Input)
Logger.log("Input Value%s",cleint_id_Input)
//Login action button
var action = CardService.newAction().setFunctionName('loginCallback');
section.addWidget(CardService.newTextButton().setText('Login').setOnClickAction(action))
card.addSection(section)
i need inputText value in "loginCallback" function
Thanks in advance
You can retrieve the inputted values as JSON object. The modified script retrieves the inputted values and displays them. So please modify this for your environment.
Modified script :
function buildAddOn() {
var card = CardService.newCardBuilder();
card.setHeader(CardService.newCardHeader().setTitle("Login Here"));
var section = CardService.newCardSection()
var cleint_id_Input = CardService.newTextInput()
.setFieldName("client_id")
.setTitle("Please enter clinet id")
var username_Input = CardService.newTextInput()
.setFieldName("username")
.setTitle("Please enter username")
var password_Input = CardService.newTextInput()
.setFieldName("password")
.setTitle("Please enter password")
section.addWidget(cleint_id_Input)
section.addWidget(username_Input)
section.addWidget(password_Input)
Logger.log("Input Value%s",cleint_id_Input)
//Login action button
var action = CardService.newAction().setFunctionName('loginCallback');
section.addWidget(CardService.newTextButton().setText('Login').setOnClickAction(action))
card.addSection(section)
return card.build() // Added
}
// Added
function loginCallback(e) {
return CardService.newCardBuilder()
.setHeader(CardService.newCardHeader().setTitle('sample'))
.addSection(CardService.newCardSection().addWidget(
CardService.newKeyValue().setContent(JSON.stringify(e.formInput, null, " ")))
)
.build();
}
Inputted values :
In your case, e of loginCallback(e) is as follows.
{
"formInput": {
"password": "###",
"client_id": "###",
"username": "###"
},
"clientPlatform": "web",
"messageMetadata": {
"messageId": "###",
"accessToken": "###"
},
"formInputs": {
"password": [
"###"
],
"client_id": [
"###"
],
"username": [
"###"
]
},
"parameters": {}
}
If I misunderstand your question, I'm sorry.
I created a GAS script file on my Drive using the example from Packt's book 'Learning Google Apps Script. My question is how do I make this into an Add-On. Not quite sure on the manifest file I need to create (even after reading https://developers.google.com/gmail/add-ons/how-tos/building).
function saveEmailAttachmentsToDrive(){
// Create 'Gmail Attachments' folder if not exists.
createFolder_('Gmail attachments');
// Get inbox threads starting from the latest one to 100.
var threads = GmailApp.getInboxThreads(0, 100);
var messages = GmailApp.getMessagesForThreads(threads);
var folderID = PropertiesService.getUserProperties()
.getProperty("FOLDER");
var file, folder = DriveApp.getFolderById(folderID);
for (var i = 0 ; i < messages.length; i++) {
for (var j = 0; j < messages[i].length; j++) {
if(!messages[i][j].isUnread()){
var msgId = messages[i][j].getId();
// Assign '' if MSG_ID is undefined.
var oldMsgId = PropertiesService.getUserProperties()
.getProperty('MSG_ID') || '';
if(msgId > oldMsgId){
var attachments = messages[i][j].getAttachments();
for (var k = 0; k < attachments.length; k++) {
PropertiesService.getUserProperties()
.setProperty('MSG_ID', messages[i][j].getId());
try {
file = folder.createFile(attachments[k]);
Utilities.sleep(1000);// Wait before next iteration.
} catch (e) {
Logger.log(e);
}
}
}
else return;
}
}
}
};
function createFolder_(name) {
var folder, folderID, found = false;
/*
* Returns collection of all user folders as an iterator.
* That means it do not return all folder names at once,
* but you should get them one by one.
*
*/
var folders = DriveApp.getFolders();
while (folders.hasNext()) {
folder = folders.next();
if (folder.getName() == name) {
folderID = folder.getId();
found = true;
break;
}
};
if (!found) {
folder = DriveApp.createFolder(name);
folderID = folder.getId();
};
PropertiesService.getUserProperties()
.setProperty("FOLDER", folderID);
return folderID;
}
My question is how do I make this into an Add-On. Not quite sure on the manifest file I need to create (even after reading https://developers.google.com/gmail/add-ons/how-tos/building).
The JSON for the manifest file for the gmail part is:
"gmail": {
"name": "My Gmail Add-on",
"logoUrl": "https://www.example.com/hosted/images/2x/my-icon.png",
"primaryColor": "#4285F4",
"secondaryColor": "#00BCD4",
"authorizationCheckFunction": "get3PAuthorizationUrls",
"contextualTriggers": [{
"unconditional": {},
"onTriggerFunction": "buildAddOn"
}]
That must be in addition to what is already there. A manifest file at it's very basic, looks like this:
{
"timeZone": "America/New_York",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER"
}
You are going to make it look like the following:
{
"timeZone": "America/New_York",
"dependencies": {
},
"gmail": {
"name": "My Gmail Add-on",
"logoUrl": "https://www.example.com/hosted/images/2x/my-icon.png",
"primaryColor": "#4285F4",
"secondaryColor": "#00BCD4",
"authorizationCheckFunction": "get3PAuthorizationUrls",
"contextualTriggers": [{
"unconditional": {},
"onTriggerFunction": "buildAddOn"
}]
},
"exceptionLogging": "STACKDRIVER"
}
Use your timeZone, and your settings. Note that there are no dependencies listed, but leave that part in.
manifest.json is generated automatically by the Apps Script engine. It is hidden by default, but you can view it by toggling View > manifest file to see the structure.
When you're ready to test the AddOn, you can go to Publish > Deploy as web add on. If you're uploading from the cloud editor, you do not need to add a separate manifest file in the web store listing.
The development documentation covers deployment methods in detail.