When you start a web development project, you have a set of requirements for which you have selected a CMS. This CMS generally covers most of the requirements - if not all - with its out-of-the-box functionality. Yet sometimes there are some requirements that it cannot cover, either because they are too specific, complex, out of the usual. In this situation, what can you do?

  • Try to find an extension or plugin of the CMS. Some CMS productions like Wordpress, Joomla have tons of plugins, so you might be lucky here.
  • If no plugin fits your requirements, you can write a plugin yourself. This requires a certain level of expertise and time.
  • You can try to write some custom code if the CMS allows it and integrate it in the CMS itself.

Since I am working on a Strapi based project and I bumped into a requirement that I could not cover with Strapi out of the box - or one that cannot be met by the API's generated by Strapi. The requirement was about capturing non-predefined fields of a form and sending this data to an email address using a simple HTML mail template and performing some checks. It is a simple requirement, nothing ground-breaking, but not something you the typical Strapi API's do cover.

It turns out that Strapi allows you to create controllers. Controllers are custom actions which process a request coming from a client. OK, so we decided to create a custom controller to implement our requirement. This controller will receive the form data and generate the text of an HTML mail and then send it using Sendgrid:

Creating a Strapi Custom Controller

In order to create a custom controller, we have to have a Strapi project already created. Check our previous blog "A practical journey to the world of headless CMS's with Strapi" to see how this is done. 

In this exercise, we are going to use a Linux shell-like, e.g. bash.

A Strapi project is typically located in a folder on your file system. We need to change the directory to this folder:

cd <strapi-project-folder>

We are going to create two directories, one for the configuration of the controller and another one for the controller itself:

mkdir -p ./api/mail/config

mkdir -p ./api/mail/controllers/

And now we create the files with a command line editor:

vim ./api/mail/config/routes.json

vim ./api/mail/controllers/Mail.js

routes.json contains the definition of the controller properties, i.e. how the controller processes requests, its path and which is the handler file (the file with the code which processes the requests):

The relevant part here is the POST request which points to this file ./api/mail/controllers/Mail.js and specifically to the send method in this file. This file is available on Gitlab. The send method in the ./api/mail/controllers/Mail.js  file looks basically like this:

There are some extra methods in the ./api/mail/controllers/Mail.js file related to processing the incoming request, extracting parameters, creating the mail template and sending the email as well as sending a message to the client. If you would like to go through the code here it is on Gitlab:


After creating these two files (./api/mail/config/routes.json, ./api/mail/controllers/Mail.js) you will need to restart the Strapi server. We had integrated our development server with Linux systemd (we recommend doing this in general) so we just used:

systemctl restart learnmeditationstrapi

which basically stops Strapi and then runs our startup script:


source /home/learnmeditation/.bashrc

cd <project-dir>

source ./sendgrid.env

yarn develop >> /var/log/<project-name>log 2>&1

And that is it. Now we have a controller mapped to the /mail path that we can test with Postman:


Strapi offers you as a developer lots of flexibility with its controllers which allow you to create custom API's easily. There are other ways to extend Strapi, like creating plugins which we will explore in an upcoming blog. But controllers are really handy and basically allow you to use the Strapi infrastructure not forcing you to install some other platform to cover custom functionality.