I have created simple Gmail addon, now I'm struggling with below strategies.
After installing the addon, when first inbox is opened, we ask basic info input from users, when he opens second mail we won't ask basic info details again.
How I can handle this?
I have tried property service but no luck.
Update
var MAX_THREADS = 5;
/**
* Returns the array of cards that should be rendered for the current
* e-mail thread. The name of this function is specified in the
* manifest 'onTriggerFunction' field, indicating that this function
* runs every time the add-on is started.
*
* @param {Object} e data provided by the Gmail UI.
* @returns {Card[]}
*/
function buildAddOn(e) {
// Activate temporary Gmail add-on scopes.
//Logger.log('E', Session.getActiveUser());
var accessToken = e.messageMetadata.accessToken;
GmailApp.setCurrentMessageAccessToken(accessToken);
var userProperties = PropertiesService.getUserProperties();
var Token = userProperties.getProperty('Token');
Logger.log('Token value:',typeof Token);
if(Token != null ){
var messageId = e.messageMetadata.messageId;
var senderData = extractSenderData(messageId);
var cards = [];
// Build a card for each recent thread from this email's sender.
if (senderData.recents.length > 0) {
senderData.recents.forEach(function(threadData) {
cards.push(buildRecentThreadCard(senderData.email, threadData));
});
} else {
// Present a blank card if there are no recent threads from
// this sender.
cards.push(CardService.newCardBuilder()
.setHeader(CardService.newCardHeader()
.setTitle('No recent threads from this sender')).build());
}
return cards;
}
else{
var cards = []
var login_card = build_login_card()
cards.push(login_card);
return cards;
}
}
/**
* This function builds a set of data about this sender's presence in your
* inbox.
*
* @param {String} messageId The message ID of the open message.
* @return {Object} a collection of sender information to display in cards.
*/
function extractSenderData(messageId) {
// Use the Gmail service to access information about this message.
var mail = GmailApp.getMessageById(messageId);
var threadId = mail.getThread().getId();
var senderEmail = extractEmailAddress(mail.getFrom());
var recentThreads = GmailApp.search('from:' + senderEmail);
var recents = [];
// Retrieve information about up to 5 recent threads from the same sender.
recentThreads.slice(0,MAX_THREADS).forEach(function(thread) {
if (thread.getId() != threadId && ! thread.isInChats()) {
recents.push({
'subject': thread.getFirstMessageSubject(),
'count': thread.getMessageCount(),
'link': 'https://mail.google.com/mail/u/0/#inbox/' + thread.getId(),
'lastDate': thread.getLastMessageDate().toDateString()
});
}
});
var senderData = {
"email": senderEmail,
'recents': recents
};
return senderData;
}
/**
* Given the result of GmailMessage.getFrom(), extract only the email address.
* getFrom() can return just the email address or a string in the form
* "Name <myemail@domain>".
*
* @param {String} sender The results returned from getFrom().
* @return {String} Only the email address.
*/
function extractEmailAddress(sender) {
var regex = /\<([^\@]+\@[^\>]+)\>/;
var email = sender; // Default to using the whole string.
var match = regex.exec(sender);
if (match) {
email = match[1];
}
return email;
}
/**
* Builds a card to display information about a recent thread from this sender.
*
* @param {String} senderEmail The sender email.
* @param {Object} threadData Infomation about the thread to display.
* @return {Card} a card that displays thread information.
*/
function buildRecentThreadCard(senderEmail, threadData) {
var card = CardService.newCardBuilder();
card.setHeader(CardService.newCardHeader().setTitle(threadData.subject));
var section = CardService.newCardSection()
.setHeader("<font color=\"#1257e0\">Recent thread</font>");
section.addWidget(CardService.newTextParagraph().setText(threadData.subject));
section.addWidget(CardService.newKeyValue()
.setTopLabel('Sender')
.setContent(senderEmail));
section.addWidget(CardService.newKeyValue()
.setTopLabel('Number of messages')
.setContent(threadData.count.toString()));
section.addWidget(CardService.newKeyValue()
.setTopLabel('Last updated')
.setContent(threadData.lastDate.toString()));
var threadLink = CardService.newOpenLink()
.setUrl(threadData.link)
.setOpenAs(CardService.OpenAs.FULL_SIZE);
var button = CardService.newTextButton()
.setText('Open Thread')
.setOpenLink(threadLink);
section.addWidget(CardService.newButtonSet().addButton(button));
card.addSection(section);
return card.build();
}
function build_login_card(){
var card = CardService.newCardBuilder();
card.setHeader(CardService.newCardHeader().setTitle("Login Here"));
var userProperties = PropertiesService.getUserProperties();
var Token = userProperties.setProperty('Token',"Token");
return card.build()
}
According to comments, the primary issue here is that uninstalling the add-on does not remove bits from the UserProperties datastore, and thus if the add-on is re-installed, the add-on configuration steps cannot be performed again.
Generic Add-on Solution
If this were not a Gmail add-on, this could be simply solved with a time-based trigger, since per documentation:
I.e., you would simply write the day's date to a key (e.g.
LAST_SEEN
) inPropertiesService#UserProperties
every day, and then check both TOKEN and LAST_SEEN when deciding which card to display.Gmail Add-on Solution:
Per Gmail add-on documentation, you cannot create or use Apps Script simple / installable triggers in a Gmail add-on. So, the easiest implementation of the solution is not available. However, we can still use this approach, by moving the region in which that
LAST_SEEN
key is updated.Right now (2018 March), the only available trigger for a Gmail add-on is the contextual trigger
unconditional
:So, if you bind to this contextual trigger, while your add-on is installed it will run a function whenever the user opens an email. The solution is then for your contextually triggered function to include the snippet
If you have other stuff to do in your contextually triggered function, that code will be uninfluenced by this addition. If you don't have a contextually triggered function, then you'd want to
return []
(an empty card stack) in order to avoid showing any UI.To use this new property, in your
buildAddon(e)
method you want to query for this value in addition to the TOKEN property you are using:uninstall
contextual trigger would be much better), but can help detect lack-of-use situationsRobert , have you tried caching the user input ?
I do caching in the event handler.
Refer cache docs