Adding additional services into Amplify
Tags: aws, cloudformation, amplify, javascript
Published: 2021-07-07 16:48:39

Michael Liendo's post [Serverless Contact Form Using AWS Amplify](https://dev.to/mtliendo/serverless-contact-form-using-aws-amplify-1e9m) reminded me of something I learnt about adding additional "not natively supported" services into Amplify.

When I say "not natively supported", I mean you can't create the resources with the cli. Rather than, Amplify doesn't support them at all. Of course your application will, you've access to the AWS SDK after all...

## Sending a simple templated email...
Like Michael's example, I wanted to simply create an email to invite people to an organisation in [the slate](https://www.theslate.co). The difference was I wanted to use an [SES email template](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/send-personalized-email-api.html), so that I could have different environmental versions. 

## SES templates?
Rather than have the actual email template like so
```javascript
await ses
  .sendEmail({
    Destination: {
      ToAddresses: [process.env.SES_EMAIL],
    },
    Source: process.env.SES_EMAIL,
    Message: {
      Subject: { Data: 'Candidate Submission' },
      Body: {
        Text: { Data: `My name is ${candidateName}. You can reach me at ${candidateEmail}` },
      },
    },
  })
  .promise()
```
You can do something like this, 
```javascript
var emailTemplate = {
  Destination: {
    ToAddresses: []
  },
  Source: `The Slate <${inviteEmail}>`,
  Template: 'SLATE_INVITE',
  TemplateData: `{ \"invited_by\":\"${userDetails.name}\", \"invite_url\": \"${url}\" }`, // THIS HAS TO BE A JSON ESCAPED STRING!?
  ReplyToAddresses: [
    `The Slate <${inviteEmail}>`
  ],
};

await ses.sendTemplatedEmail(emailTemplate).promise();
```

`SLATE_INVITE` is a reference to an HTML and Text email template held in SES, and it will accept the references and data in `TemplateData` to be rendered in the template. To me it's a nice / clearer way of making changes to the template.

## Kicking it up a notch
For some reason, I've no idea why, I decided to put the HTML and text templates into `/amplify/backend/email`. 

Then in my infinite wisdom I wondered, could I make a Cloudformation template for this? 

My rational was that I could deploy environmental/versioned templates alongside everything else, and if I had to spin the slate up on a different AWS account, it wouldn't be a problem. The short answer is [yes](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ses-template.html), yes you can. 

As you can imagine, it didn't take long to go "If I have a cloudformation template, could add it to the existing Amplify cloudformation set-up?". Again, turns out you can do this too. 

## Extending your Amplify Cloudformations
You may have never have noticed, but there is a file at `/amplify/backend/backend-config.json` that describes your amplify resources, e.g.
```javascript
"storage": {
  "slate": {
    "service": "DynamoDB",
    "providerPlugin": "awscloudformation"
  }
},
```
The format of the json describes two things;
1. "Storage" is both the "Category" you see in the cli and a folder (`/amplify/backend/storage`)
2. "slate" is "Resource name" you see in the cli and a folder (`/amplify/backend/storage/slate`) holding the cloudformation template

If you were to add something like 
```javascript
"email": {
  "invite": {
    "service": "SES",
    "providerPlugin": "awscloudformation"
  }
},
```
In theory it will be picked up.

In theory you say?
Yes - because you need to have `/amplify/#current-cloud-backend/amplify-meta.json` refreshed to see your new service in the cli. 

Once that happens, when you will see your new custom service and it will execute as part of the cloudformation stack. If it isn't there, it won't.