---
# System prepended metadata

title: 'RFC: Email service'

---

# RFC: Email service

## Ventura email API

- Integrated with admin templates defined in GO
- Support for nested templates and translations
- Can be consumed from external services like Make via Hasura actions
- Allow basic customization 

------------------------------------------------------------------------------------------

#### Sending email

<details>
 <summary><code>POST</code> <code><b>/send</b></code> <code>(using a GO template)</code></summary>

##### Parameters

 | name      |  type     | data type               | description                                                           |
 |-----------|-----------|-------------------------|-----------------------------------------------------------------------|
 | templateId |  required | string   | UUID of `email_template` entity in GO |
 | from | required | string | sender email address
 | to | required | string | receiver email address
 | bcc | optional | string | blind carbon copy email address
 | lang | optional | string | `locale_id` if it's a multilang template. By default, will be the master language (en).
 | variables | optional | object | variables to be injected in the template
 | attachments | optional | string[] | list of object names (file key) stored in Google Cloud Storage. These will be independent to the static attachments the template may have.
 | brandStyles | optional | boolean | `false` by default. Include branding header and footer. This option will overwrite the value defined in the original template. 
 | customStyle | optional | string | custom CSS string 
 

##### Responses

| http code     | content-type                      | response                                                            |
 |---------------|-----------------------------------|---------------------------------------------------------------------|
 | `200`         | `application/json`        | <pre>{<br>  "status": "success",<br>  "message": "Email queued successfully",<br>  "data": {<br>    "emailId": "23e4567-e89b-12d3-a456-426614174000",<br>    "templateId": "23e4567-e89b-12d3-a456-426614174000",<br>    "from": "karen@gmail.com",<br>    "to": "sophia@example.com",<br>    "bcc": "jhon@example.com",<br>    "attachments": [<br>      "mybucket/pfs/something.pdf"<br>    ],<br>    "body": "Hello Sophia, this is a <b>test</b>"<br>  }<br>}</pre> |                               |
 | `400`         | `application/json`                | <pre>{<br>  "status": "error",<br>  "message": "invalid request",<br>  "error": "Template `23e4567-e89b-12d3-a456-426614174000` not found"<br>}</pre>                            |
  | `400`         | `application/json`                | <pre>{<br>  "status": "error",<br>  "message": "invalid request",<br>  "error": "Variable `FAKE_VAR` not found in template `23e4567-e89b-12d3-a456-426614174000`"<br>}</pre>                            |
 | `400`         | `application/json`                | <pre>{<br>  "status": "error",<br>  "message": "invalid request",<br>  "error": "`witherror@something` is not a valid email address"<br>}</pre>                            |
 | `400`         | `application/json`                | <pre>{<br>  "status": "error",<br>  "message": "invalid request",<br>  "error": "attachment `mybucket/pfs/something.pdf` not found"<br>}</pre>                            |
 | `500`         | `application/json`                | <pre>{<br>  "status": "error",<br>  "message": "server error",<br>  "error": "unknown error: something went wrong, please check the logs"<br>}</pre>                            |                                       |


</details>

------------------------------------------------------------------------------------------


<details>
 <summary>Implementation details</summary>

The most important entities that hold complex logic are templates, variables and attachments. Here explained in context:

#### Template

Template entity holds the main data about the email, such as:

- Subject and Body with conditional blocks handling
- Translations
- Linked brands

 with this new service, we have to add support for:
 - A `boolean` flag to enable/disable branding decoration (logos, header, footer). e.g: `is_brand_style_enabled`

#### Variables

It's kay-value where the key must match the names of the variables defined in the template. The GO must extend the current functionality to support new types of variables.

There are 3 types of variables:

##### Simple text

The value is a string or a number, most common variables will be just like the following example:

```typescript
export const standard: SendEmailRequest = {
  templateId: "23e4567-e89b-12d3-a456-426614174000",
  from: "sophia@galapatours.com",
  to: "karen@gmail.com",
  bcc: "jhon@example.com",
  attachments: ["mybucket/pfs/something.pdf"],
  variables: {
    VAR_1: "test",
    CLIENT_NAME: "Karen",
    REMAINING_TICKETS: 11,
  },
};
```

##### Formatted text

The value is an object with  2 keys:

```typescript
export type FormattedVar = {
  format: "html" | "draft" | "text";
  content: string;
};
```

By default, all variables saved in GO are `"draft"` which is a tree-like format but services that consume this API could use html as well:

```typescript
export const standardWithHtmlVar: SendEmailRequest = {
  templateId: "23e4567-e89b-12d3-a456-426614174000",
  from: "sophia@galapatours.com",
  to: "karen@gmail.com",
  bcc: "jhon@example.com",
  attachments: ["mybucket/pfs/something.pdf"],
  variables: {
    VAR_1: {
      format: "html",
      content: "<b>test</b>",
    },
    CLIENT_NAME: "Karen", // this is equivalent to { format: "text", content: "Karen"}
  },
};

```

##### Nested Template 

This type of variable unlocks the possibility to have nested templates, as the previous, it is also an object (or array of objects) but with the following shape:

```typescript
export type NestedTemplateVar = {
  templateId: string;
  variables?: Record<string, string | number>;
}[];
```

The `templateId` represents a different template than the original and `variables` represents variables of simple text or formatted text and are scoped in to only this template. The API will support just one (1) level of nested TemplateVariables.

Example:

```typescript
export const withNested: SendEmailRequest = {
  templateId: "23e4567-e89b-12d3-a456-426614174000",
  from: "sophia@galapatours.com",
  to: "karen@gmail.com",
  bcc: "jhon@example.com",
  attachments: ["mybucket/pfs/something.pdf"],
  variables: {
    VAR_1: "test",
    CLIENT_NAME: "Karen",
    MY_NESTED_VAR: {
      templateId: "23e4567-e89b-12d3-a456-426614174000",
      variables: {
        VAR_1: "test nested",
      },
    },
  },
};
```

You can also pass an array of `NestedTemplateVar` to handle an iterable block of templates:

```typescript
export const withNestedIterable: SendEmailRequest = {
  templateId: "23e4567-e89b-12d3-a456-426614174000",
  from: "sophia@galapatours.com",
  to: "karen@gmail.com",
  bcc: "jhon@example.com",
  attachments: ["mybucket/pfs/something.pdf"],
  variables: {
    VAR_1: "test",
    CLIENT_NAME: "Karen",
    MY_NESTED_VAR: [
      {
        templateId: "23e4567-e89b-12d3-a456-426614174000",
        variables: {
          VAR_1: "test nested 1",
        },
      },
      {
        templateId: "23e4567-e89b-12d3-a456-426614174000",
        variables: {
          VAR_1: "test nested 2",
        },
      },
    ],
  },
};
```

This is useful to render structured lists in the email at scale since all the features of email template admin applies here, with some limitations:

- **Attachments**: they will be ignored
- **Lang**: will be use the same specified in the request or in the root template, make sense, right?
- **Nested template variables**: only support one(1) level of nesting.

###### Impact in GO

The **email variables admin** needs to have a way to link an existing template as a variable, and should be filtreable within the variables admin. And the **template admin** should be able to filter templates that are used as variables. This can be achieved with a new foreign field `template_id` in the `email_variable` table.

Addionally, the **template admin** the variables chooser (dropdown) and the embed variable table (in Email tab) should distinguish the if the type of variable is a normal one (simple text) or a nested one (email template var). This can be done using different icons for each one.

#### Attachments

Attachments must include the bucket in the path because the file could be retrieved from anywhere in the Ventura's cloud workspace.

```
["mybucket/pfs/103849.pdf", "mybucket/imgs/xmas_card_japan.jpg"]
```

</details>

### Flow
    
![email flow](https://hackmd.io/_uploads/SyNs7B5Hn.png)


#### Interfaces
<details>
 <summary>Typescript</summary>

```typescript
/* Request */

export interface SendEmailRequest {
  templateId: string;
  from: string;
  to: string;
  bcc?: string;
  attachments?: string[];
  variables?: Record<
    string,
    string | number | FormattedVar | NestedTemplateVar | NestedTemplateVar[]
  >;
}

export type NestedTemplateVar = {
  templateId: string;
  variables?: Record<string, string | number>;
};

export type FormattedVar = {
  format: "html" | "draft" | "text";
  content: string;
};

/* Response */

export interface SendEmailResponse {
  status: "success" | "error";
  message: string;
  data?: {
    emailId: string;
    templateId: string;
    from: string;
    to: string;
    bcc: string;
    attachments: string[];
    body: string;
  };
  error?: string;
}

```


</details>

------------------------------------------------------------------------------------------


