2

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).

Rubén
  • 34,714
  • 9
  • 70
  • 166
  • You must pay a one-time $5 dollar U.S. fee to have an add-on published. Have you done that? It looks like you are trying to create a GMail add-on, and there is a special `gmail` property to be configured in the manifest for that. Other types of add-on's do not need anything done to the manifest file. The documentation you need to look at is: [Link to Documentation](https://developers.google.com/gmail/add-ons/concepts/manifests#manifest_structure_for_gmail_add-ons) You should be able to just copy that JSON, and then modify the settings. – Alan Wells Feb 13 '18 at 23:01
  • Tried to copy and past the manifest you linked me to, but get 'Unexpected character ('-'(code 46)): was expecting double quote to start field name at [Source: { ...' – Dan Goldenberg Feb 14 '18 at 20:53
  • I added an answer. – Alan Wells Feb 14 '18 at 21:42

2 Answers2

3

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.

Alan Wells
  • 30,746
  • 15
  • 104
  • 152
  • Thanks Sandy for the manifest file. That one worked. So now do I select Deploy as web add-on or do I select Deploy from manifest? – Dan Goldenberg Feb 15 '18 at 16:54
  • 1
    You must use "Deploy from Manifest" There is more information in the Quick Start documentation [Link to Quickstart for Gmail Add-on](https://developers.google.com/gmail/add-ons/guides/quickstart) – Alan Wells Feb 15 '18 at 18:09
  • Thanks again. When I go to Deploy from manifest, I now get two deployments. I just did the 'Get Id' on the head deployment and successfully installed it. But when I run it I get: Error with the add-on. Run time error. Script function not found: buildAddOn – Dan Goldenberg Feb 15 '18 at 22:52
  • Look at the setting `"onTriggerFunction": "buildAddOn"` That tries to run a function named `buildAddOn`. The `onTriggerFunction` is what causes the add-on to run when certain conditions are met. In the manifest you currently have, the condition is `unconditional`, so the add-on tries to run the function `buildAddOn` regardless of the content in the email. What happens is, the user opens an email, and the add-on looks for the condition defined in `contextualTriggers` setting. You have a `saveEmailAttachmentsToDrive` function. Replace `buildAddOn` with `saveEmailAttachmentsToDrive`. – Alan Wells Feb 16 '18 at 02:01
  • Thanks again. Did make that change. But now when I run the add-on, I get: Error with the add-on. Run time error. The value returned from Apps Script has a type that cannot be used by the add-ons platform. Also make sure to call build on any builder before returning it. Value: Null, undefined, empty or blank – Dan Goldenberg Feb 16 '18 at 13:27
  • I'd need to debug the code for you to know what is causing the error. The problem that you are having now, seems like it's from the code and not the manifest file. One thing you should do is read the troubleshooting guide. [Link to troubleshooting guide](https://developers.google.com/apps-script/guides/support/troubleshooting) If you can determine what line is causing the error, you can post a different question. Hopefully, your original question is answered, or I at least help you enough to make some progress. – Alan Wells Feb 16 '18 at 16:52
1

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.

Brian
  • 4,274
  • 2
  • 27
  • 55
  • I select Publish --> Deploy as web add-on and not Publish --> Deploy from manifest? – Dan Goldenberg Feb 13 '18 at 21:43
  • Is your add-on is a standalone script? (not bound to Doc, Sheet, Slide or Form). If yes, select 'deploy as web add-on'. For Gmail add-ons, select 'deploy from manifest'. – Anton Dementiev Feb 13 '18 at 23:52
  • It's a standalone script. I want it to be available to be used in certain mail db's. When I select Deploy as web add-on, there is a drop down selection it makes me select of Docs, Sheets, Forms, & Slides. I really don't want any of these. So I am a bit confused. Thanks for your help in advance. – Dan Goldenberg Feb 14 '18 at 15:13