> For the complete documentation index, see [llms.txt](https://kinesis-school-of-programming.gitbook.io/nestjs-unleashed/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kinesis-school-of-programming.gitbook.io/nestjs-unleashed/further-improvements-tips-module/improvements/sending-emails.md).

# Sending emails

A useful feature in many contexts.

When a user creates an account, we could send an email to him confirming that his account has been successfully created.

> This solution was inspired by this [article](https://notiz.dev/blog/send-emails-with-nestjs) from **Marc Stammerjohann** (blog).

First, we should install **handlebars**. It is a **template engine**, capable of generating an HTML template dynamically. It allows for holding the email structure while also receiving data.

```shellscript
yarn add handlebars
```

After that, install the dependencies required for email handling.

```shellscript
yarn add @nestjs-modules/mailer nodemailer
```

{% hint style="info" %}
Note that, in this case, we use a **community** package instead of an official one.
{% endhint %}

We should then adopt an **email provider**, so that we can actually send emails through the system. Here, we'll use [Mailpit](https://mailpit.axllent.org/) due to its very simple setup, as it will run locally in Docker. We should then define its service in the <mark style="color:purple;">compose.yml</mark> file.

```yml
mailpit:
  image: axllent/mailpit
  ports:
    - ${MAIL_PORT}:1025
    - 8025:8025
  environment:
    MP_SMTP_AUTH: ${MAIL_USER}:${MAIL_PASSWORD}
    MP_SMTP_AUTH_ALLOW_INSECURE: true
```

{% hint style="info" %}
Note the following:

* It has a dedicated port for its **UI** (<mark style="color:blue;">8025</mark>)
* <mark style="color:blue;">`ALLOW_INSECURE`</mark> allows for authentication without **TLS**
  {% endhint %}

But we still don't have those mail credentials, so don't start the container yet. Create then, the environment variables for the **email server**.

```dotenv
MAIL_USER = mailuser
MAIL_PASSWORD = pass123
MAIL_HOST = localhost
MAIL_PORT = 1025
MAIL_FROM = noreply@conrod.com
```

{% hint style="info" %}
Here, the <mark style="color:blue;">`MAIL_PORT`</mark> is <mark style="color:blue;">1025</mark> due to Mailpit, but in <mark style="color:purple;">.env.example</mark> you may use <mark style="color:blue;">587</mark>, which is the standard port for **SMTP** submission with **STARTTLS**.
{% endhint %}

Also update the <mark style="color:blue;">`ENV_VALIDATION_SCHEMA`</mark>.

```typescript
MAIL_USER: z.string(),
MAIL_PASSWORD: z.string(),
MAIL_HOST: z.hostname(),
MAIL_PORT: ze.port,
MAIL_FROM: z.email(),
```

We may then start the container.

```shellscript
docker compose up -d
```

Now, create a module and a service for **mailing**. Also export the service.

```sh
nest g mo mail
nest g s mail
```

In the same directory, create the folder <mark style="color:purple;">templates</mark>, for holding the **handlebars templates**.

As we are used to, the next step is to create a configuration namespace. We may do so in <mark style="color:purple;">mail</mark>/<mark style="color:purple;">config</mark>/<mark style="color:purple;">mail.config</mark>. We use the credentials to create the <mark style="color:blue;">`transport`</mark> URL, very similarly to the database configuration. Also, a **default** is used for the <mark style="color:blue;">`from`</mark> email, and the template engine is also configured.

```typescript
export default registerAs('mail', () => {
  const user = env.MAIL_USER!;
  const password = env.MAIL_PASSWORD!;
  const host = env.MAIL_HOST!;
  const port = env.MAIL_PORT!;
  const from = env.MAIL_FROM!;

  const transport = `smtp://${user}:${password}@${host}:${port}`;

  const config = {
    transport,
    defaults: { from: `No Reply <${from}>` },
    template: {
      dir: resolve(import.meta.dirname, '..', 'templates'),
      adapter: new HandlebarsAdapter(),
      options: { strict: true },
    },
  } as const satisfies MailerOptions;
  return config;
});
```

{% hint style="info" %}
Note the following about the <mark style="color:blue;">`template`</mark>:

* The <mark style="color:blue;">`dir`</mark> location is resolved from <mark style="color:blue;">`import.meta.dirname`</mark>, which is the current folder
* The <mark style="color:blue;">`HandlebarsAdapter`</mark> should be imported manually from <mark style="color:blue;">`@nestjs-modules/mailer/adapters/handlebars.adapter`</mark>
* The <mark style="color:blue;">`strict`</mark> option enforces that all fields are passed to the template
  {% endhint %}

In the <mark style="color:blue;">`MailModule`</mark>, import the <mark style="color:blue;">`MailerModule`</mark>, passing this configuration.

```typescript
MailerModule.forRootAsync(mailConfig.asProvider())
```

Then, inside the <mark style="color:purple;">templates</mark> folder, we may create the template <mark style="color:purple;">account-confirmation.hbs</mark>.

```handlebars
<p>Hello {{name}},</p>

<p>Your account has been successfully created!</p>

<p><strong>The Conrod Shop</strong></p>
```

However, the templates are not included in the **build** by default. Due to this, let's go to the <mark style="color:purple;">nest-cli.json</mark> file and add the following inside the <mark style="color:blue;">`compilerOptions`</mark>. We also enable **watch mode** for them.

```json
"assets": ["**/*.hbs"],
"watchAssets": true
```

Before proceeding to the <mark style="color:blue;">`MailService`</mark> and implementing the email-related logic, let's create the file <mark style="color:purple;">mail</mark>/<mark style="color:purple;">interfaces</mark>/<mark style="color:purple;">mail-payload.interface</mark>. With this, we can have the payloads for all email methods defined here, centrally.

```typescript
export interface MailPayload {
  sendAccountConfirmation: {
    name: User['name'];
    email: User['email'];
  };
}
```

Now, in the <mark style="color:blue;">`MailService`</mark>, at the bottom, create a type that will shape the service as a class with methods sharing the same names as the <mark style="color:blue;">`MailPayload`</mark> properties, and the params of each method will be the types of these properties. They also have the same return as the <mark style="color:blue;">`sendMail()`</mark> method of the <mark style="color:blue;">`mailerService`</mark>. Lastly, make the service implement it.

```typescript
type IMailService = {
  [K in keyof MailPayload]: (data: MailPayload[K]) => Promise<SentMessageInfo>;
};
```

After that, we may inject the <mark style="color:blue;">`MailerService`</mark>. Finally, implement the method for sending an "account created" confirmation email to the user. We also pass the <mark style="color:blue;">`context`</mark> with the data for the template. And return the result just in case we may want to inspect it.

```typescript
sendAccountConfirmation(data: MailPayload['sendAccountConfirmation']) {
  const { name, email } = data;

  const mailData = {
    to: email,
    subject: 'Account created',
    template: './account-confirmation',
    context: { name },
  } as const satisfies ISendMailOptions;

  return this.mailerService.sendMail(mailData);
}
```

Now, we should import the <mark style="color:blue;">`MailModule`</mark> in the <mark style="color:blue;">`UsersModule`</mark>, and inject the <mark style="color:blue;">`MailService`</mark> in the <mark style="color:blue;">`UsersSubscriber`</mark>. It is here that we'll send the email after the account is created, in order to prevent bloating the <mark style="color:blue;">`UsersService`</mark>. Lastly, to only send this email after the user is successfully created, this will be done in the <mark style="color:blue;">`afterInsert()`</mark> listener.

```typescript
async afterInsert(event: InsertEvent<User>) {
  const { entity: user } = event;
  const { name, email } = user;

  const mailPayload = { name, email } as const;
  await this.mailService.sendAccountConfirmation(mailPayload);
}
```

{% hint style="info" %}
This adds a delay to the user creation. We'll learn how to avoid this problem in the **Queues** module.
{% endhint %}

<mark style="color:green;">**Commit**</mark> - Sending email when user is created
