A Serverless Function for Sending Emails on IBM Cloud

4 min read

Easily send emails using SendGrid, MailJet or your own SMTP server.

You have created your app on IBM Cloud. Now, you want to extend its functionality to send out emails. You could integrate all the email functionality into your app or just call out to another microservice. I opted for the latter for my apps. 

I created a small, reusable, serverless action using IBM Cloud Functions. That action takes care of interacting with the email server. All my app needs to do is invoke the action with the email payload. I tested it with my custom domain and my own SMTP server as well as with email delivery services like SendGrid and MailJet.

The serverless action and instructions are available in the IBM-Cloud/cloudmailer GitHub repository. In the following, I discuss how it works, how to configure it and what you need to know to have your app send an email like the one below:

Sample email with HTML content, including link.

Sample email with HTML content, including link.

Serverless action to send emails

In the introduction, I mentioned that I created a small, reusable, serverless action to send out emails: sendEmail. Serverless computing provisions compute resources on demand. You only pay for the consumed resources when your code is active. Thus, it is ideal for a microservice to send emails. IBM Cloud offers both IBM Cloud Code Engine and IBM Cloud Functions for serverless computing. For this microservice, I opted for a Cloud Functions action because of the small project size and the Nodemailer module already included in the standard Node.js runtime.

With a module to handle the SMTP-related functionality conveniently available, all the action has to perform is to retrieve the configuration and email properties from the available parameters, establish a connection to the SMTP server and pass on the email object. Let's take a look into what data is needed:

Code section from sendEmail action.

Code section from sendEmail action.

Configure the email delivery service

The properties to establish a connection to an SMTP server are the same, regardless of whether you are using an email delivery service like SendGrid, MailJet, etc. or interacting with your email provider/your own email server. It is the host and the port along with a username/password combination, all packed into a JSON object "server":

{
    "server": {
        "host": "smtp.example.com",
        "port" : 465,
        "id": "security@example.com",
        "password": "strong-password"
    }
}

Because of SPAM and other abuse, often the typical SMTP port 25 is either not available or blocked by the compute environment. Thus, expect to find port numbers like 465 or 587. Instead of the username and password, an API key could be used. In the case of SendGrid and some others, then the username would be "apikey" and the password value the actual API key. Other vendors use an API key as username and a special secret key as password.

With that server configuration available, I first deploy the sendEmail action and then bind the SMTP configuration as default parameters to the action. There are different ways to accomplish this and the GitHub repository includes steps for the IBM Cloud command line interface (CLI). But, you could also just copy and paste the source code for the action and use the IBM Cloud Functions web UI.

Provide the email as payload

Once you deploy the action and have the SMTP server configuration ready, it's time to send an email. The "email" is another JSON object with a structure like this:

{
   "email":{
            "sender": "Henrik Loeser <henrik@example.com>",
            "receiver": "data-henrik@example.com",
            "subject": "Sample email for blog post",
            "text": "see the HTML text",
            "html": "<html><h1>Hello world!</h1>Check out the <a href=\"https://github.com/IBM-Cloud/cloudmailer\">code on GitHub</a>.<h3>Let's talk emails</h3>To receive emails, someone has to send them.</html>"
   }
}

The shown values result in an email like the one shown in the first screenshot above. It consists of the sender, receiver, the email subject and one of (or both) the text or HTML version of the email body. Note that for some email services, you can only use verified email addresses as sender. The value for receiver can be a comma-separated list of email addresses. As you can see, the value  for "html" can include formatting, hyperlinks and more.

The email object needs to be passed into the action when invoking it (i.e., when calling this email microservice).

Ready, set, send email

To send emails, you have to invoke the Cloud Functions actions. There are multiple ways of how to do this and I describe them in README in the GitHub repository. The easiest way for testing probably is to use the CLI or Cloud Functions web UI. If you configured the SMTP server as default parameters, the following command would send out an email with its properties read from the file email.json:

ibmcloud fn action invoke cloudmailer/sendEmail -r  -P email.json 

To utilize the action from your app as microservice, you can either invoke the action via the Cloud Functions REST API or turn it into a web action. For the latter, you would need to set an additional flag and decide how to secure it.

Conclusions

In this blog post, I have shown that it is simple to set up a microservice to send out emails via SMTP. I have implemented it as serverless action with IBM Cloud Functions and in Node.js. The service can be used on its own or utilized by apps to send out status emails or alerts. In the blog post "How to Get IBM Cloud Security Advisor Alerts via Slack or Email" from last year, I discussed how to set up email alerts for security issues. A recent follow-up post shows how to use SMTP servers similar to what I discussed today.

Note that the Nodemailer module offers more message options, including attachments to send images or PDF documents and, of course, setting email addresses on CC and BCC. This could be added to the code. Open a GitHub issue if you need help. If you have other feedback, suggestions, or questions about this post, please reach out to me on Twitter (@data_henrik) or LinkedIn

Be the first to hear about news, product updates, and innovation from IBM Cloud