# Mailer

Currently we can have one of **two email services**. Both required additional packages installed, .env setup, also you must register in their services. They have pretty similar approach. They have their own documentation with this service, so we will not repeat ourselves here, but just consider how it works for us.

## AWS

At this link you will read all the necessary information about how to install AWS into our project. Here we just mentioned about AWS email service.

[Here ](https://aws.amazon.com/ses/)you can read the official documentation about their email service.

Before we start you must set the .env constants with you AWS SES User Credentials:

* `EMAIL_SERVICE`
* `EMAIL_SENDER`
* `AWS_SES_REGION`
* `AWS_SES_ACCESS_KEY`
* `AWS_SES_SECRET_ACCESS_KEY`

## SendGrid

Same all for SendGrid. Just follow their [guide ](https://www.twilio.com/docs/sendgrid/for-developers?_gl=1*1uvsnyx*_gcl_aw*R0NMLjE3MjcwODE3MzcuQ2owS0NRandvOFMzQmhEZUFSSXNBRlJta09QV25qMXlkSktkdFFZOTVURkpqRmlTRFFlbXdMbFJkcm5HTHdzYVRNZ21WQXVPYi1vQl8tc2FBa05fRUFMd193Y0I.*_gcl_au*MTQ1MzgwMzM3MS4xNzI3MDgxMzI4*_ga*Nzc0MzQ4NTYuMTcyNzA4MTMyOA..*_ga_8W5LR442LD*MTczMDEyMzEzMS4zLjEuMTczMDEyMzI3MC4wLjAuMA..)from documentation.

.env:

* EMAIL\_SERVICE
* EMAIL\_SENDER
* SENDGRID\_API\_KEY

{% hint style="danger" %}
N.B. if you cannot find such constants in .env file, than it can be found in *.../src/constants.ts.* This was done within the security framework if somewhere something becomes unavailable.
{% endhint %}

{% hint style="warning" %}
N.B. EMAIL\_SERVICE and EMAIL\_SENDER are the place were we specify what kind of service we will use. This constants are common to both services.
{% endhint %}

## Structure

Pretty simple and common form for Nest.JS. Email have it's own module where all the magic happens.

...api/src/email/

But there you can find another folder for AWS and SendGrid services separately, email.service.ts uses one of those.

In ***.../api/src/common/interfaces/*** you will find interfaces for email templates.

Email templates lays in .../api/email-templates/

All this must done/created before sending email. After you do this, just add the method into the service file and use it where you need it.  For example invitation email that we've mentioned in [Team Management.](/intercode-saas-kit/pages/team-management.md)

```typescript
    async createInvitation(body: InvitationDto, user: JwtUserPayload) {
        if (body.role === TeamRole.Owner) {
            throw new HttpException(
                {
                    message: 'Error',
                    description: "You can't add owner to an existing team",
                    code: 'ADD_OWNER_TO_TEAM',
                },
                HttpStatus.BAD_REQUEST
            );
        }

        const teamId = body.teamId || user.teamId;

        const team = await this.teamEntityRepository.findOne({
            where: { id: teamId },
            relations: ['memberships'],
        });

        const userMembership = await this.teamMembershipRepository.findOne({
            where: { team: { id: teamId }, user: { id: user.id } },
        });

        // we should check permission here, because when the user try to invite people
        // immediately after team creation he doesn't have team id and guard can't check permission
        if (!userMembership || userMembership.role === TeamRole.Viewer) {
            throw new ForbiddenException('Access denied');
        }

        const invitedUser = await this.userRepository.findOne({ where: { email: body.email }, withDeleted: true });

        if (!team) {
            throw new HttpException(
                {
                    message: 'Error',
                    description: 'Team not found',
                    code: 'TEAM_NOT_FOUND',
                },
                HttpStatus.BAD_REQUEST
            );
        }

        if (team.usersLimit <= team.memberships.length) {
            throw new HttpException(
                {
                    message: 'Error',
                    description: 'Team is full',
                    code: 'TEAM_FULL',
                },
                HttpStatus.BAD_REQUEST
            );
        }

        if (invitedUser) {
            const isMembershipValid = await this.teamMembershipService.validateMembership(teamId, invitedUser.id);

            if (isMembershipValid) {
                throw new HttpException(
                    {
                        message: 'Error',
                        description: 'User is already a member of this team',
                        code: 'USER_ALREADY_MEMBER',
                    },
                    HttpStatus.BAD_REQUEST
                );
            }

            await this.teamMembershipService.create(
                { id: invitedUser.id, firstName: body.firstName, lastName: body.lastName, phone: body.phone },
                teamId,
                body.role
            );

            this.emailService.sendExistedUserInvitationEmail(body.email, team.name);

            return {
                message: `Invitation email send`,
                description: 'Wait for invited person to finish his registration',
            };
        }

        const invite = await this.userService.createInvitedUser(body);

        await this.teamMembershipService.create(
            { id: invite.user.id, firstName: body.firstName, lastName: body.lastName, phone: body.phone },
            team.id,
            body.role
        );

        this.emailService.sendInvitationEmail(body.email, invite.token, team.name);

        return {
            message: `Invitation email send`,
            description: 'Wait for invited person to finish his registration',
        };
    }
```

Here you can find event two different emails that we send in two different situations.

## Conclusions

1. Register a user account on one or both services.
2. Install all the necessary packages.
3. Setup .env file and constants.ts
4. Create email templates, interfaces for that templates and module for email service.
5. Use email method where you need.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://intercode.gitbook.io/intercode-saas-kit/external-integrations/mailer.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
