In 2012 while working at eFront, I was in charge of the development of some Microsoft Office addin projects. At that time, we leveraged the COM/VSTO technologies to craft these extensions. The next year, I heard about this new generation of Office Addins. They were actually web addins, the model was entirely different from what I used to develop. In those days Office was about 1 billion users and the promise of a marketplace to distribute to so many business and individual users was definitely exciting. I developed quickly my first addin to see what were the capacities of this new technology. This first one was an Excel add-in allowing you to sync your spreadsheet with Google Analytics data. In 2015, I bootstrapped a second one: KMailPrint. It is actually a simple virtual printer for Outlook emails. In few words, it allows you to transform an email into a nicely formatted PDF, far better from what you can do with Outlook Desktop or with the virtual printer of your browser. I thought that this project was not really worth a post on this blog, I never wrote about it. Now I believe that making a short retrospective about its evolutions over the years could actually be of some interest.
At the beginning, the capabilities of Excel addins were really limited so I dropped my first Excel addin. Yet KMailPrint found a certain traction, seeing the printing count reach several hundred of emails daily. Noticing that it was actually helping people, I decided to maintain the project over the years, dedicating at most few hours per year to it. Now it is a 6-year-old project and the total counter reaches roughly a million of generated PDFs. There is no API and these are all manual triggers from end-users. Far from being amazing, there is definitely a certain interest so I think the project is worth the maintenance. In this post I will detail all the major engineering evolutions that the project has seen.
The global architecture evolution
At first there was only one monolithic server responsible to handle everything. Among the main responsibilities, it was serving the Single Page Application powering the web addin, handling the virtual printer logic and finally handling all the server-side logic that is mainly Exchange Web Services processing.
Over the years, this monolith gave birth to a more service oriented approach. The frontend is now served statically and independently of the application server or the virtual printer service.
Evolution of the frontend
The very first version started with KnockoutJS, reusing portions of my Excel/Google Analytics addin that was written with it. Quickly after, I decided to rewrite with AngularJS. When it comes to the tooling, the dependencies were managed by Bower and frontend build tasks were automated by Grunt. Everything was handled with Visual Studio directly in the development solution. The developer experience was actually pretty nice for a web based project at that time.
Evolution of the backend
The very first backend was implemented as a C# ASP.NET MVC using the .NET Framework 4.5. Then I stripped all dynamic views rendering to transform it into a real .NET Core Web API. Now it uses the latest .NET Core 3.1 version. To be honest, my main motivation by migrating to .NET Core was the ability to deploy as a containerized application for easier hosting and maintenance. Now that I work with a MacBook, I am glad to be able to work natively with C#/.NET, something that was not possible 6 years ago.
Evolution of the printer
In its first version, the virtual printer used an underlying engine made with a PhantomJS headless browser. Precisely, I used Powershell instrumentation techniques to manage the PhantomJS processes responsible for printing the targeted HTML content. It lasted 2 years but having so many child processes in the application server was problematic. I decided to switch to a Node/ExpressJS REST API service, handling the virtual printing, the underlying engine remained backed by PhantomJS.
The installation was more and more problematic and I performed a migration to Docker for the virtual printer service.
PhantomJS was known to be end-of-life for many years. In 2021, I finally decided to drop my legacy PhantomJS Docker images (that I could not build anymore) and rewrote the virtual printer with ExpressJS and Puppeteer. This later project is based on the Chromium Embedded Framework. My virtual printer Express project is now a containerized REST API service implemented in Typescript with Node and ExpressJS.
Evolution of the infrastructure
In 2015 at the very beginning, the infrastructure constraints were problematic. I attempted to leverage the first versions of Azure App Services. That was not possible: the OS exposed by the underlying Azure VM did not have the necessary graphic libraries to perform the rasterizing tasks required to the virtual impression. I was forced to fallback to a more heavy solution using the Azure Cloud Services which were powered with a full capacity Windows VM.
This situation lasted for a couple of years, I even had a bare Ubuntu Linux virtual machine when the PDF printer was first migrated to Node. Finally, the migration to .NET Core and the containerization of the PhantomJS-based app allowed me to move everything back to Container Azure Web App. Having work with many Docker orchestration services (Amazon ECS, Nomad or even a little of Kubernetes), I believe that for a basic usage such as the one exposed here, it remains one of the easiest ways to run a couple of containers on the cloud.
In addition, I followed the evolution of the Azure BlobStorage (equivalent of Amazon S3). The recent evolution allowed me to benefit from the latest blob lifecycle management features.
Finally, the fresh new static frontend written in React is hosted with Azure Static Web Apps. I have already spoke in good favor about Azure Static Web Apps. I confirm that it is really well adapted for hosting a frontend SPA application as well. The Github actions are also good friends to integrate quickly a CI workflow.
Infrastructure costs are limited, because KMailPrint does not expose any external APIs the number of requests is fairly limited. I manage to host all my containers on top of an A1 Azure VM costing less than a couples of dollars per month.
That’s it for the time traveling in the history of this small project. I encourage you to maintain your side projects, even the small ones: one day you will be proud of the work accomplished. Having hundreds of people using it everyday was a strong motivator for me. To be frank, I was tempted to let it go last year. Now that I work at iAdvize where our main technology for frontend development is React, KMailPrint was a great opportunity for me to learn React with a real project in my hands.