Connect to outlook for calendar event add

Hey all,

I’m looking to create a webhook automation that will add events to an outlook calendar upon saving a form in appsheet. I’m currently using the free version of appsheet but my company is signed up with microsoft. Has anyone done this before? This is where my brain goes dumb..

Thanks

1 Like

You’d need to create a script that would accomplish what you’re wanting, and I don’t think that’s allowed under the free plan.

But you could go to your favorite LLM and ask it for a google apps script that you could call from your app that would integrate with Microsoft’s APIs.

1 Like

Would I get a 403 error code due to using the free version of appsheet?

1 Like

No, it should work. I just did a test with a couple of free accounts I have, and they all worked.

  • I was able to use the API to pull records from the free app
    • Proving you can use the AppSheet API externally with a free account
  • I was able to use a webhook step in automation to call an external API
    • Proving you can use webhooks in a free account

Here’s my testing setup (so you can copy and try yourself):

  1. Create a Google Apps Script deployed web app that creates an API you can interact with
    • I created one that sends whatever it receives to your email
  2. Create a scheduled bot in your app with a single task, to send something to your API

If things work, you’ll receive an email from the script.


The Script

First you need to create the API, which sounds more complicated than it actually is. :wink:

steps

:right_arrow: Open Apps Script  |  Google for Developers

:right_arrow: Create a new project

  • Name: Test API

:right_arrow: Add the following code

Test API deployed web app code
// Set your email here
const MY_EMAIL = 'YOUR_EMAIL'; // CHANGE THIS TO YOUR EMAIL

function doPost(e) {
  let debugInfo = {};
  let emailSubject = 'Webhook Debug';
  let emailBody = '';
  
  try {
    const timestamp = new Date().toISOString();
    debugInfo.timestamp = timestamp;
    debugInfo.receivedEvent = true;
    
    // Capture everything about the request
    debugInfo.hasParameter = !!e.parameter;
    debugInfo.hasPostData = !!e.postData;
    debugInfo.hasParameters = !!e.parameters;
    
    if (e.parameter) {
      debugInfo.parameter = e.parameter;
    }
    
    if (e.postData) {
      debugInfo.postData = {
        length: e.postData.length,
        type: e.postData.type,
        contents: e.postData.contents
      };
    }
    
    if (e.parameters) {
      debugInfo.parameters = e.parameters;
    }
    
    // Try to parse body if it exists
    let parsedBody = null;
    if (e.postData && e.postData.contents) {
      try {
        parsedBody = JSON.parse(e.postData.contents);
        debugInfo.parsedBodySuccess = true;
        debugInfo.parsedBody = parsedBody;
      } catch (parseError) {
        debugInfo.parsedBodySuccess = false;
        debugInfo.parseError = parseError.toString();
        debugInfo.rawContents = e.postData.contents;
      }
    }
    
    emailSubject = `Webhook SUCCESS - ${timestamp}`;
    emailBody = `Webhook received successfully!\n\nDebug Info:\n${JSON.stringify(debugInfo, null, 2)}`;
    
    // Send success email with fallback methods
    try {
      // Try multiple email methods
      const userEmail = Session.getActiveUser().getEmail();
      debugInfo.userEmail = userEmail;
      
      if (!userEmail) {
        // Try hardcoded email if session fails
        GmailApp.sendEmail(MY_EMAIL, emailSubject, emailBody);
      } else {
        GmailApp.sendEmail(userEmail, emailSubject, emailBody);
      }
      debugInfo.emailSent = true;
    } catch (emailError) {
      debugInfo.emailSent = false;
      debugInfo.emailError = emailError.toString();
      
      // Try MailApp as fallback
      try {
        MailApp.sendEmail(MY_EMAIL, emailSubject, emailBody);
        debugInfo.fallbackEmailSent = true;
      } catch (fallbackError) {
        debugInfo.fallbackEmailError = fallbackError.toString();
      }
    }
    
    // Return success response
    return ContentService
      .createTextOutput(JSON.stringify({
        status: 'success',
        message: 'Webhook processed',
        timestamp: timestamp,
        debug: debugInfo
      }))
      .setMimeType(ContentService.MimeType.JSON);
      
  } catch (mainError) {
    // Something went wrong - send error email
    debugInfo.mainError = mainError.toString();
    debugInfo.errorStack = mainError.stack;
    
    try {
      GmailApp.sendEmail(
        Session.getActiveUser().getEmail(),
        'Webhook ERROR',
        `Webhook failed!\n\nError: ${mainError.toString()}\n\nStack: ${mainError.stack}\n\nDebug Info:\n${JSON.stringify(debugInfo, null, 2)}`
      );
    } catch (emailError) {
      // Can't even send email
    }
    
    return ContentService
      .createTextOutput(JSON.stringify({
        status: 'error',
        message: mainError.toString(),
        debug: debugInfo
      }))
      .setMimeType(ContentService.MimeType.JSON);
  }
}

function doGet(e) {
  try {
    GmailApp.sendEmail(
      Session.getActiveUser().getEmail(),
      'Webhook GET Test',
      `GET request received.\n\nParameters: ${JSON.stringify(e.parameter || {}, null, 2)}`
    );
    
    return ContentService
      .createTextOutput(JSON.stringify({
        status: 'success',
        message: 'Webhook tester is running',
        timestamp: new Date().toISOString()
      }))
      .setMimeType(ContentService.MimeType.JSON);
  } catch (error) {
    return ContentService
      .createTextOutput(JSON.stringify({
        status: 'error',
        message: error.toString()
      }))
      .setMimeType(ContentService.MimeType.JSON);
  }
}

function testWebhook() {
  const testData = {
    parameter: {},
    postData: {
      length: 45,
      type: 'application/json',
      contents: '{"event":"test","data":{"id":123,"name":"test"}}'
    },
    parameters: {}
  };
  
  const result = doPost(testData);
  return `Test completed. Check email for results. Response: ${result.getContent()}`;
}

:right_arrow: Save everything, then deploy as a web app

  • Deploy button > New Deployment
  • Select Type (Top Left Gear) > Web App
  • Description: doesn’t matter
  • Web app:
    • Execute as: ME
    • Who has access: ANYONE

:right_arrow: Deploy (blue button, bottom right)

:right_arrow: Copy the “Web app URL”

:right_arrow: Authorize the script by hitting the “Run” button

  • This will bring up a bunch of authorizations
  • Approve everything so the script can run

The Webhook Task

Next you need to create a test automation in your app, with a webhook task to send some test data to your test API.

steps

:right_arrow: Open your app, go to Automation, make a new automation (doesn’t matter what table)

:right_arrow: Configure event > Create new event (bottom option)

  • Event Name : doesn’t matter
  • Event source: scheduled
  • the rest of the settings don’t matter

:right_arrow: Add a new step

  • Type: Call a webhook
  • Preset: Custom
  • URL: paste the URL on your clipboard (from your API)
  • HTTP Verb: Post
  • HTTP Content Type: JSON
  • Body
{
  "Test": "Value", 
  "Another": "Value"
}
  • Ignore the rest

:right_arrow: Save everything


Testing

Now that everything is in place, let’s actually test things.

:right_arrow: Click the “Run” button for your scheduled automation

  • Pro Tip: the reason we make this automation “scheduled” was because then we get the run button, so we can literally now run the automation with the press of a button. Very helpful for testing things. :wink:

You should receive an email with the contents.



To debug what’s not working, take a look at the automation monitor, and the audit logs.