Google Cloud Functions: Sending emails using Gmail SMTP and Nodemailer
Tags: node, javascript, gcp, serverless
Published: 2019-04-12 16:16:52

---
title: Google Cloud Functions: Sending emails using Gmail SMTP and Nodemailer
published: true
description: 
tags: node, javascript, gcp, serverless
---

I have a very simple website hosted on a GCP storage segment and now I need to make it slightly less simple by adding a contact form. Then I realized that the easiest was to use everything I already have more or less in place: I could write a Function using the Google Cloud Platform that would send the emails using the GSuite account I use for the same domain. Let's see how everything goes!

## The set-up

We need to use the **OAuth2** authentication method, and for that to work we first need to go to [the gcp console](https://console.cloud.google.com/iam-admin/serviceaccounts) and select (or create!) a service account. Once this is done, click on the **More** button (the three dots) and then click **Create key**, this will take you to the process of creating a service key and will download a JSON file with all the data we need.

Now, we have to go to the [GSuite control panel](https://admin.google.com) and enable de API for the service account. Go to **Security -> Advanced security -> Manage API client access** and enter your `client_id` and `https://mail.google.com/` for the API scope. You can find your `client_id` in the JSON file.

## The Google Cloud Function

To create a Google Cloud Function, we have to go to the [Functions Overview page](https://console.cloud.google.com/functions/list) in the gcp console, click on **Create function** and give it a name. Then we need to select the **HTTP Trigger** and the **Node** runtime. You would also probably want to select the lower memory allocation possible. For now, we will use the inline editor, so we will later need to paste the contents of our `index.js` and `package.json` there. We need to set the **Function to execute**, `sendMail` in my case; and then we can click on **more** to set some environment variables. Our code will use the following:

`GMAIL_ADDRESS`: This is the user that we will use for authenticating, bear in mind it has to be a **real** user and not an alias.
`CLIENT_ID`: found in the JSON file.
`PRIVATE_KEY`: found in the JSON file.

We will also set `MAIL_FROM`, `MAIL_TO` and `MAIL_BCC`; these can be sent in the request but we want to have a fallback as they won't be mandatory.


## The code

The only dependency we are going to have is Nodemailer, so:
`npm i --S nodemailer`

Now, let's take a look at the code:

```javascript
exports.sendMail = (req, res) => {}
```
For this function to work, our **sendMail** method will provide two arguments: the request and the response.

```javascript
  if (!req.body.subject || !req.body.text) {
    res.status(422).send({
      error: {
        code: 422,
        message: "Missing arguments"
      }
    });
    return;
  }
```
First thing we do is check if we have everything we need to carry on, in my case I only care if I have an actual email to send, other parameters like `from` or `to` are optional as I will store environment variables for them, but you can check for whatever you need to!

```javascript
const nodeMailer = require("nodemailer");

const transporter = nodeMailer.createTransport({
  host: "smtp.gmail.com",
  port: 465,
  secure: true,
  auth: {
    type: "OAuth2",
    user: process.env.GMAIL_ADDRESS,
    serviceClient: process.env.CLIENT_ID,
    privateKey: process.env.PRIVATE_KEY.replace(/\\n/g, "\n")
  }
});
```
Now we create a transport with our configuration. It will take the values from the environment variables we previously defined. Note that we are doing a string replacement as the platform would have escaped the `\n` in our key, if we don't do this the private key won't be valid.

```javascript
const mailOptions = {
  from: req.body.from || process.env.MAIL_FROM,
  to: req.body.to || process.env.MAIL_TO,
  bcc: req.body.bcc || process.env.MAIL_BCC,
  subject: req.body.subject,
  text: req.body.text
};
```
Now we define our mail options, again, these may be different from what you need, you can check the [documentation](https://nodemailer.com/message/) for more detail on what's available.

```javascript
transporter
    .sendMail(mailOptions)
    .then(() => {
      res.status(200).send({
        data: {
          code: 200,
          message: "Mail sent"
        }
      });
    })
    .catch(e => {
      res.status(500).send({
        error: {
          code: 500,
          message: e.toString()
        }
      });
    });
```
Finally, we try to send the email and return the appropriate response. You can check the full code on [github](https://github.com/imaka/GCloudFunction-SendMail)

## Syncing your repo

You probably noticed that there are several options to upload the code to your Function, one of them is attaching a Cloud Source repository... and that's great because then you can maintain your function just by pushing your code to the repo. My problem is I like to use GitHub, and that's not an option here... But we can **mirror** our repos!

We need to add a new Cloud Source repository on [Google Source Repositories](https://source.cloud.google.com/onboarding/welcome). Click on **Add repository** and select **Connect external repository**. Then, select the project where you have your Function and choose your connector (GitHub or Bitbucket). Next thing to do is authorize Cloud Source Repository to store your credentials, follow the steps to connect with your account and select the repo you want to associate with your Cloud Source repo. The name of the repository will have `github_` or `bitbucket` added to the beginning of its name, and will automatically in sync with your original repository.

Once we have our Cloud Source repository ready, we can go back to our Function, click **edit** and select Cloud Source Repository as source: fill in the repository name and the branch or tag you want to link, and you are ready to go!