A lot of users want to send messages and have them arrive at a later point in time. There are various situtioans where scheduling messages instead of sending them right away comes in handy:

  • Teachers: Schedule tasks and solutions for students.

  • Teams: Postpone messages to prevent them from disrupting mates outside of business hours or on the weekend.

  • Organisation: Make announcements at specific times without being online.

  • Personal: Get things off your mind by setting reminders to yourself or someone else in advance.

What it does

The app allows you to draft a message via message extension or bot dialog and schedule it for a specific date and time in the future. The message delivery is handled by cloud services so you don't even need to be online when the message will be sent.

If you change your mind about a scheduled message, you can always cancel it (e.g. through the app's dashboard tab). There you also get a good overview of all messages and whether they're still planned or already sent.

How We built it

The app is built with TypeScript running on Node.js and the Express framework. The server is running on Azure AppService. It's integrated with a Bot Channel Registration through the Botbuilder SDK to handle conversations and message extension commands. Delivery of messages that are scheduled through the message extension or a bot dialog is based on Azure Service Bus and CosmosDB - both providing encryption at-rest and secure data transfer (something we're always focusing on).

The app tabs are plain HTML pages served by the Node.js server. We went for a simple and performant setup that works well with the Teams UX. It integrates the Teams JavaScript SDK to facilitate single sign-on in connection with some API endpoints for managing scheduled messages.

The customer portal uses the Pug template language and is also served by the Node.js server. Here we again implemented a login based Active Directory so that admins can purchase subscriptions for their organization. Payments are securely handled through the Stripe payment provider. We're using Stripe's hosted checkout and billing portal to enable maximum compliance and have various billing features available out of the box.

Challenges We ran into

Partner Center

Signing up for the partner center with our existing organization was cumbersome. First we didn't receive activation codes, then our sign-up wasn't properly connected to our existing tenant. The actual submission process for the app was also quite the challenge, the communication could definitely be improved (e.g. time to respond, reporting format).

Concepts & Making Everything Work Together

Although we're not new to web app development, it was quite a challenge to wrap our heads around the available concepts in Teams apps and how they can fit together. Making authentication work at all points (bot, message extension, tab, external customer portal) proofed to be especially difficult.

Developing as a Team

Working on the same software with multiple developers is always a bit more difficult when you're tightly coupled to a particular cloud provider. Building a Teams app had a couple more places that you'd have to keep in mind when working as a team. Luckily, we were able to reach out to the community and gain some good tips and a whole new blog post on this.

Project Setup

Finding a good baseline for development was still a challenge. There are some starting points, but in the end we've built our own project setup that deviates from what's out there in various points, putting an emphasis on TypeScript / type-safety, cross-platform (one of us develops on Ubuntu, the other on Windows) and CI / CD.


The APIs are nice, but we've hit a couple point where they're just off. Some properties are type and documented wrongly (e.g. context activity property localTimezone), other's are missing (e.g. context activity property rawLocalTimestamp). Also, the authentication APIs seemed to be in need of unification.

Legal Stuff

Publishing a Teams app in combination with an SaaS offer had us going through so many different documents and worry about numerous details. First, we thought we could deploy an SaaS through Microsoft, however, we eventually rolled our own solution based on Stripe due to legal considerations and worries about the user-flow.

Accomplishments that We're proud of

Getting the app done at all and in time. Something specific might be figuring out the delayed delivery implementation based on a service queue and the ComosDB.

What We learned

A bunch of technologies:

  • Node.js & Express
  • Azure Cloud
  • CosmosDB (+ stored procedures)
  • Azure Service Bus
  • Azure Active Directory
  • Microsoft Teams app development
  • Bot development

Also, the whole way for bringing an idea into the Microsoft AppSource store. All of these learnings are a great basis for future projects.

What's next for Send Later

We're looking forward to having the first users enjoy our app. Launching our landing page provided a couple interesting leads and we can't wait to onboard users and boost their productivity. Then we'd like to extend the app based on their feedback. We've already got a little backlog of features which are waiting to be worked on (e.g. rich formatting, timezone selection, send when available). Also, we're keen to write-up our learnings into some blog posts to help other developers to get into developing apps for Microsoft Teams.

Share this project: