Serverless functions for marketing automation

Marketing automation is an essential field for startups that need to react fact and focus on one thing: bring value to their clients. Repetitive and time-consuming tasks should be automated.

Nowadays, many solutions exist to help non-technical people automate those tasks like Zapier, Autopilot, and, of course, our friends at Webmecanik.

Sometimes however, you may need very specific integrations that are not possible to do with those all-in-one solutions. Here is where developers come! But, as you may know, developers are lazy... And spin-up a project, test it and deploy it in production is a large work for just doing some clever automations.

But hey, we are in 2020 ; and serverless functions are a thing!

What are serverless functions?

Let's start with a funny tweet from @iamdevloper:

Serverless is server less in the same way a beef burger is vegetarian because you didn't personally see the cow being killed.

— I Am Devloper (@iamdevloper) May 1, 2019

Surely you understood from this joke that serverless is a misleading term. There are servers that run the code, just as a standard web application. So, why do we call it like this? The main motivation behind serverless functions is to focus only on the code and don't a care a second about the deployment, server provisioning or configuration.

The execution environment is entirely managed by the cloud provider: Amazon Web Services Lambda, Google Cloud Functions or Azure Functions. Just upload your source code to them and they will handle the deployment, and scale automatically if the load increases.

The cherry on the cake is that you only pay for the time the functions are running. So, if your automation only runs for a few seconds each day, you'll pay almost nothing.

The downside is that, generally, the runtime environment is constrained by the cloud provider. For example, Google Cloud Functions only supports NodeJS, Python or Go programs. Besides, you won't be able to install more system packages than the ones that are already installed. If you rely on a specific package or language, serverless functions won't work for you (in that case, containers seem more appropriate).

Another issue is vendor lock-in: each cloud provider has its own way of implementing serverless functions, so a code that will work in AWS Lambda likely won't work in Google Cloud Functions without a few adjustments.

In the case of marketing automation though, this is OK: generally, it just involves to get data from one service and put it in another. Each function will consist of a few lines of code and HTTP requests!

React to events: webhooks to the rescue!

Now, let's say we want to add a contact to a mailing list whenever we create a new deal in our CRM. Without webhooks, the logic of our automation would look like this:

Automation: Is there a new deal?

CRM: No.

One minute later

Automation: Is there a new deal?

CRM: No.

One minute later

Automation: Is there a new deal?

CRM: No.

One minute later

Automation: Is there a new deal?

CRM: Yes. The contact is Arthur Pendagron, its email is [email protected].

Automation: Ok. Hey, mailing list! Add Arthur Pendagron, its email is [email protected].

Mailing list: Ok, done.

As you see from this play, our automation would harass the CRM every minute to check if there is something new. Not very effective, and a total waste of resources.

Hopefully, we have something that could help: webhooks! They are a way of telling the service we want to get the data from to notify our automation when something happens. This way, our automation is only called when there is something to do. Let's see our new play with webhooks:

Automation: Hey, CRM! Tell me when a new deal is created.

CRM: Ok.

One eternity later

CRM: Hey, automation! A new deal was created. The contact is Arthur Pendagron, its email is [email protected].

Automation: Ok. Hey, mailing list! Add Arthur Pendagron, its email is [email protected].

Mailing list: Ok, done.

Far more efficient ⚡️ Funny things start when you trigger more events after reacting to other events. For example, we could set up a webhook that tell the email marketing service that a new contact was added in the mailing list, so that it could subscribe it to our e-mailing scenario!

Mind-blowing

A bit of code

Now, how does it look like as actual code? Let's see a short example with Google Cloud Functions. We assume we have pipedrive (CRM) and mailjet (mailing service) clients at hand to help us:

def pipedrive_to_mailjet(request: flask.Request) -> Tuple[str, int]:
    """Add new deals contacts to a Mailjet list."""
    webhook_meta = request.json["meta"]
    deal_id = webhook_meta["id"]
    deal = pipedrive.get_deal(deal_id)

    mailjet.add_contact(
        deal["person_id"]["email"][0]["value"],
        deal["person_id"]["name"],
        MAILJET_LIST_ID,
    )

    return ("", 201)

That's it! Get the data we were notified about, add it to another service. Deploy this code into production only requires one command:

gcloud functions deploy pipedrive_to_mailjet --runtime python37 --trigger-http --allow-unauthenticated

After a few minutes, your automation will be ready with a nice HTTP endpoint that webhooks can actually call.

You may have noticed the --trigger-http option. Actually, serverless functions can also be triggered by message queues. We'll talk about this in a future post.

Automate the automation

Inception

Great! We've created a working automation: just a few lines of code, a simple deployment process, our dreams have come true. But remember: developers are super lazy.

If we have one automation, it's manageable. But usually, we have dozens of them. Each time we update the code, we would have to re-deploy them individually. That's boring. And error-prone!

The secret is to automate the deployments of our cloud functions. How? With Continuous Integration (CI)! This would require a dedicated article but, in a nutshell, those are technologies that provide an environment to script and execute actions whenever we add changes to the source code. Travis, GitLab CI or the youngest one, GitHub Actions, are some of them.

Generally, CI configuration files look like this:

name: Build

on: [push, pull_request]

jobs:

  deploy:
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/master'

    steps:
    - uses: actions/[email protected]
    - name: Deploy pipedrive_to_mailjet
      uses: actions-hub/[email protected]
      env:
        PROJECT_ID: ${{ secrets.GCLOUD_PROJECT_ID }}
        APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
      with:
        args: functions deploy pipedrive_to_mailjet --runtime python37 --trigger-http --allow-unauthenticated

You see that we have several steps, including one that execute the deploy command we saw earlier. If we have several automations to deploy, we just have to add it once in this configuration file. Now, each time we update the code, all automations will be automatically deployed.

Conclusion

It's key to understand that, while automations are useful to help grow the business, they are not a core part of it. Hence, they should be written and deployed quickly so that developers can focus on the product. We saw that serverless functions and CI can greatly help in that matter.

At BeeMyDesk, we rely on those technologies to automate our CRM pipelines and customer success actions. It's important to us to keep up with the latest technologies and select the ones that will maximize the impact of the developers time on the business growth.