VitNode

Email Service

Sending emails in VitNode.

In VitNode we're implementing helper to send emails with React Email which allows you to create beautiful responsive emails using React.

Provider

Before you start sending emails, you need to install the provider. Choose one of the following:

Usage

test.service.ts
import { Injectable } from '@nestjs/common';
import { EmailHelperService } from 'vitnode-backend/helpers/email/email.service'; 
import { TestArgs } from './test.dto';
 
@Injectable()
export class TestService {
  constructor(
    private readonly databaseServices: DatabaseService,
    private readonly mailService: EmailHelperService, 
  ) {}
 
  show({ email }: TestArgs): string {
    const user = await this.databaseService.db.query.core_users.findFirst({
      where: (table, { eq }) => eq(table.email, email),
    });
 
    if (!user) {
      throw new NotFoundError('User');
    }
 

    await this.mailService.send({
      to: user.email,
      subject: 'Test email subject',
      message: 'Test email message',
      previewText: 'Test email preview text',
      user,
    });
 
    return 'Success!';
  }
}

Templates using React

Create a new file for your email template.

example.email.tsx
import { Text } from '@react-email/components';
import React from 'react';
 
export const SendForgotPasswordTemplateEmail = ({
  user,
}: {
  user: {
    name: string;
  };
}) => {
  return <Text>Hi! This is a test for {user.name}</Text>;
};

You can read more about React Email here.

Import into your service and use it like this:

test.service.ts
import { Injectable } from '@nestjs/common';
import { EmailHelperService } from 'vitnode-backend/helpers/email/email.service';
import { TestArgs } from './test.dto';
import { SendForgotPasswordTemplateEmail } from './example.email'; 
 
@Injectable()
export class TestService {
  constructor(
    private readonly databaseServices: DatabaseService,
    private readonly mailService: EmailHelperService,
  ) {}
 
  show({ email }: TestArgs): string {
    const user = await this.databaseService.db.query.core_users.findFirst({
      where: (table, { eq }) => eq(table.email, email),
      columns: {
        id: true,
        name: true,
        email: true,
        language: true,
      },
    });
 
    if (!user) {
      throw new NotFoundError('User');
    }
 
    await this.mailService.send({
      to: user.email,
      subject: 'Test email subject',

      message: SendForgotPasswordTemplateEmail({
        user,
      }),
      previewText: 'Test email preview text',
      user,
    });
 
    return 'Success!';
  }
}

Internationalization (i18n)

We're created a helper function getTranslationForEmail(namespace, language) to translate the email templates. You can use it like this:

import React from 'react';
import { Text } from '@react-email/components';
import { getTranslationForEmail } from 'vitnode-backend/helpers/email/email'; 
 
export const ExampleTemplateEmail = ({
  user,
}: {
  user: {
    language: string; 
    name: string;
  };
}) => {
  const t = getTranslationForEmail('admin.core.email', user.language); 
 
  return (
    <Text>
      Hi! This is a test for {user.name} - {t('surfix_user')}
    </Text>
  );
};

...or in your service.

namespaces are working the same as in the frontend.

Template Helpers

We're providing some helper functions to make your life easier. Using this.emailHelpersService.getHelpersForEmail() you can get the following values like:

  • frontend_url,
  • site_name,
  • site_short_name
example.email.tsx
import React from 'react';
import { Text, Button } from '@react-email/components';
import { getTranslationForEmail } from 'vitnode-backend/helpers/email/email';
import { GetHelpersForEmailType } from 'vitnode-backend/helpers/email/email-helpers.type'; 
 
export const ExampleTemplateEmail = ({
  user,
  helpers, 
}: {
  helpers: GetHelpersForEmailType; 
  user: {
    language: string;
    name: string;
  };
}) => {
  const t = getTranslationForEmail('admin.core.email', user.language);
 
  return (
    <Text>
      Hi! This is a test for {user.name} - {t('surfix_user')}
      <Button
        className="bg-primary text-primary-foreground rounded-md px-4 py-2.5 text-sm font-medium"
        href={`${helpers.frontend_url}/test`} 
      >
        {t('button')}
      </Button>
    </Text>
  );
};

Modify the service to inject EmailHelpersService.

test.service.ts
import { Injectable, Inject } from '@nestjs/common'; 
import { EmailHelperService } from 'vitnode-backend/helpers/email/email.service';
import type { EmailHelpersServiceType } from 'vitnode-backend/helpers/email/email-helpers.type'; 
import { TestArgs } from './test.dto';
import { ExampleTemplateEmail } from './example.email';
 
@Injectable()
export class TestService {
  constructor(
    private readonly databaseServices: DatabaseService,
    private readonly mailService: EmailService,
    @Inject('EmailHelpersService') 
    private readonly emailHelpersService: EmailHelperService, 
  ) {}
 
  async show({ email }: TestArgs): Promise<string> {
    const user = await this.databaseService.db.query.core_users.findFirst({
      where: (table, { eq }) => eq(table.email, email),
    });
 
    if (!user) {
      throw new NotFoundError('User');
    }
 
    await this.mailService.send({
      to: user.email,
      subject: 'Test email subject',
      message: SendForgotPasswordTemplateEmail({
        user,
        helpers: await this.emailHelpersService.getHelpersForEmail(), 
      }),
      previewText: 'Test email preview text',
      user,
    });
 
    return 'Success!';
  }
}

Checking if email is enabled

You can check if email is enabled by using this.mailService.checkIfEnable():

test.service.ts
import { EmailHelperService } from 'vitnode-backend/helpers/email/email.service';
 
@Injectable()
export class TestService {
  constructor(private readonly mailService: EmailHelperService) {}
 
  show() {
    if (this.mailService.checkIfEnable()) {
      // Do something
    }
  }
}

On this page