Aplicações de software modernas frequentemente dependem da comunicação por e-mail para interagir com os usuários. Elas podem enviar códigos de autenticação durante tentativas de login, e-mails de marketing ou boletins informativos, por exemplo. Isso significa que notificações por e-mail são tipicamente o meio mais comum de comunicação com os usuários.

Neste tutorial, você aprenderá a projetar modelos de e-mail impressionantes com React Email e enviá-los usando Resend – uma plataforma de API de e-mail simples e poderosa.

Pré-requisitos

Para aproveitar ao máximo este tutorial, você deve ter um entendimento básico de React ou Next.js.

Também utilizaremos as seguintes ferramentas:

  • React Email: Uma biblioteca que permite criar modelos de e-mail lindamente projetados usando componentes React.

  • Resend: Uma plataforma de API simples e poderosa para enviar e-mails de suas aplicações.

Como Construir a Aplicação com Next.js

Nesta seção, você criará uma aplicação simples de suporte ao cliente. O aplicativo incluirá um formulário para os usuários enviarem suas dúvidas, o que acionará uma notificação por e-mail confirmando que um ticket de suporte foi criado.

Para começar, primeiro vamos configurar a interface do usuário e um endpoint de API.

Execute o seguinte comando para criar um novo projeto Next.js em TypeScript:

npx create-next-app react-email-resend

Atualize o arquivo app/page.tsx para renderizar um formulário que colete os detalhes do cliente, incluindo seu nome completo, endereço de e-mail, o assunto do ticket e uma mensagem detalhada descrevendo o problema. Quando o formulário for enviado, os dados de entrada são registrados no console usando a função handleSubmit.

"use client";
import support from "@/app/images/support.jpg";
import { useState } from "react";
import Image from "next/image";

export default function Page() {
    //👇🏻 estados de entrada
    const [name, setName] = useState<string>("");
    const [email, setEmail] = useState<string>("");
    const [subject, setSubject] = useState<string>("");
    const [content, setContent] = useState<string>("");

    const handleSubmit = async (e: React.FormEvent) => {
        e.preventDefault();
        //👇🏻 registrar a entrada do usuário
        console.log({ name, email, subject, content });
    };
return ({/** -- elementos da UI -- */})
}

Retorne os elementos da UI do formulário que aceitam o nome completo do usuário, endereço de e-mail, assunto do ticket e uma mensagem detalhada descrevendo o problema.

    return (
        <main className='w-full min-h-screen flex items-center justify-between'>
                <form className='w-full' onSubmit={handleSubmit}>
                    <label htmlFor='name' className='opacity-60'>
                        Full Name
                    </label>
                    <input
                        type='text'
                        className='w-full px-4 py-3 border-[1px] mb-3 border-gray-300 rounded-sm'
                        id='name'
                        required
                        value={name}
                        onChange={(e) => setName(e.target.value)}
                    />

                    <label htmlFor='email' className='opacity-60'>
                        Email Address
                    </label>
                    <input
                        type='email'
                        className='w-full px-4 py-3 border-[1px] mb-3 border-gray-300 rounded-sm'
                        id='email'
                        value={email}
                        onChange={(e) => setEmail(e.target.value)}
                        required
                    />

                    <label htmlFor='subject' className='opacity-60'>
                        Subject
                    </label>
                    <input
                        type='text'
                        className='w-full px-4 py-3 border-[1px] mb-3 border-gray-300 rounded-sm'
                        id='subject'
                        value={subject}
                        onChange={(e) => setSubject(e.target.value)}
                        required
                    />

                    <label htmlFor='message' className='opacity-60'>
                        Message
                    </label>
                    <textarea
                        rows={7}
                        className='w-full px-4 py-3 border-[1px] mb-3 border-gray-300 rounded-sm'
                        id='message'
                        required
                        value={content}
                        onChange={(e) => setContent(e.target.value)}
                    />

                    <button className='w-full bg-blue-500 py-4 px-3 rounded-md font-bold text-blue-50'>
                        SEND MESSAGE
                    </button>
                </form>
            </div>
        </main>
    );

Aqui está a página resultante do componente:

Em seguida, crie um endpoint de API (/api/route.ts) que aceita a entrada do cliente.

cd app
mkdir api && cd api
touch route.ts

Copie o seguinte código para o arquivo api/route.ts. O endpoint da API registra a entrada do cliente no console ao recebê-la.

import { NextRequest, NextResponse } from "next/server";

export async function POST(req: NextRequest) {
    const { name, email, subject, content } = await req.json();
    //👇🏻 registrar o conteúdo
    console.log({ name, email, subject, content });
    return NextResponse.json({
        message: "Email sent successfully",
        data,
 });
}

Atualize a função handleSubmit para enviar os dados do cliente para o endpoint da API e retornar a resposta em JSON:

const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();

    try {
        const response = await fetch("/api", {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
            },
            body: JSON.stringify({ name, email, subject, content }),
        });
        const data = await response.json();
        alert(data.message);
    } catch (error) {
        console.error(error);
        alert("An error occurred, please try again later");
    }
    setName("");
    setEmail("");
    setSubject("");
    setContent("");
};

Parabéns! Você configurou a coleta e submissão de dados. Nas próximas seções, vou guiá-lo na criação e envio de modelos de e-mail com React Email e Resend.

Como Criar Modelos de Email usando React Email

React Email permite que você construa e envie componentes de e-mail usando React e TypeScript. Ele suporta vários clientes de e-mail, incluindo Gmail, Yahoo Mail, Outlook e Apple Mail.

React Email também fornece múltiplos componentes de UI que permitem personalizar os modelos de e-mail de acordo com o layout preferido usando componentes React JSX/TSX.

Instale o pacote React Email e seus componentes executando o trecho de código abaixo:

npm install react-email -D -E
npm install @react-email/components -E

Inclua este script no seu arquivo package.json. Ele direciona o React Email para onde os modelos de e-mail estão localizados em seu projeto.

  "scripts": {
    "email": "email dev --dir src/emails"
  },

Uma das funcionalidades do React Email é a capacidade de visualizar seu modelo de e-mail no navegador durante o desenvolvimento, permitindo que você veja como ele aparecerá no e-mail do destinatário.

Então, a seguir, crie uma pasta emails contendo um arquivo TicketCreated.tsx dentro da pasta src do Next.js e copie o seguinte trecho de código para o arquivo:

import * as React from "react";
import {
    Body,
    Container,
    Head,
    Heading,
    Hr,
    Html,
    Link,
    Preview,
    Text,
    Tailwind,
} from "@react-email/components";

interface TicketCreatedProps {
    username: string;
    ticketID: string;
}

const baseUrl = process.env.VERCEL_URL || "http://localhost:3000";

No trecho de código acima, importamos os componentes necessários para construir o modelo de e-mail.

Em seguida, adicione o componente TicketCreated ao arquivo para renderizar o modelo de e-mail usando componentes React Email.

export const TicketCreated = ({ username, ticketID }: TicketCreatedProps) => {
    return (
        <Html>
            <Head />
            <Preview>Support Ticket Confirmation Email 🎉</Preview>
            <Tailwind>
                <Body className='bg-white my-auto mx-auto font-sans px-2'>
                    <Container className='border border-solid border-[#eaeaea] rounded my-[40px] mx-auto p-[20px] max-w-[465px]'>
                        <Heading className='text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0'>
                            Your Ticket has been created
                        </Heading>
                        <Text className='text-black text-[14px] leading-[24px]'>
                            Hello {username},
                        </Text>
                        <Text className='text-black text-[14px] leading-[24px]'>
                            <strong>Support Ticket</strong> (
                            <Link
                                href={`${baseUrl}/ticket/${ticketID}`}
                                className='text-blue-600 no-underline'
                            >
                                {`#${ticketID}`}
                            </Link>
                            ) has been created successfully.
                        </Text>

                        <Text className='text-black text-[14px] leading-[24px]'>
                            The Support team will review your ticket and get back to you
                            shortly.
                        </Text>

                        <Hr className='border border-solid border-[#eaeaea] my-[26px] mx-0 w-full' />
                        <Text className='text-[#666666] text-[12px] leading-[24px]'>
                            This message was intended for{" "}
                            <span className='text-black'>{username}</span>. If you did not
                            create this ticket, please ignore this email.
                        </Text>
                    </Container>
                </Body>
            </Tailwind>
        </Html>
    );
};

Finalmente, exporte-o e adicione valores padrão para as props:

TicketCreated.PreviewProps = {
    username: "alanturing",
    ticketID: "9083475",
} as TicketCreatedProps;

export default TicketCreated;

Execute npm run email no seu terminal para visualizar o modelo de e-mail.

Este modelo de email notifica os clientes que seu ticket de suporte foi criado e que alguém da equipe de suporte entrará em contato com eles.

O React Email oferece uma variedade de modelos de email pré-desenhados, facilitando a criação de emails lindamente estilizados para diferentes fins. Você pode conferir o demo disponível para ver exemplos do que é possível.

Como Enviar Emails com Resend

O Resend é uma API de email simples que permite enviar emails dentro da sua aplicação de software. Ele suporta uma variedade de linguagens de programação, incluindo JavaScript (Next.js, Express, Node.js), Python, PHP, Go e Rust, entre outras.

O Resend e o React Email podem ser facilmente integrados, uma vez que o co-fundador do Resend, Bu Kinoshita, também é o criador do React Email.

Crie uma conta no Resend. Depois de fazer login, vá para a seção das chaves de API no seu painel e copie sua chave de API em um arquivo .env.local.

//👇🏻 .env.local file
RESEND_API_KEY=<RESEND_API_KEY>

//👇🏻 arquivo .env.local

import { NextRequest, NextResponse } from "next/server";
Atualize o endpoint da API para enviar um email usando o modelo do React Email, conforme mostrado abaixo:
import { v4 as generateID } from "uuid";
//👇🏻 função geradora de ID de bilhete
import TicketCreated from "@/emails/TicketCreated";
//👇🏻 importa o modelo de email
import { Resend } from "resend";
const resend = new Resend(process.env.RESEND_API_KEY);

export async function POST(req: NextRequest) {
    //👇🏻 importa Reenviar
    const { name, email, subject, content } = await req.json();
    //👇🏏 aceita a entrada do cliente pelo frontend
    console.log({ name, email, subject, content });
    //👇🏻 registra-os
    const { data, error } = await resend.emails.send({
        from: "Acme <[email protected]>",
        to: [email],
        subject: "Ticket Confirmation Email 🎉",
        react: TicketCreated({ username: name, ticketID: generateID() }),
    });

    if (error) {
        return NextResponse.json(
            { message: "Error sending email" },
            { status: 500 }
        );
    }

    return NextResponse.json({
        message: "Email sent successfully",
        data,
    });
}

//👇🏻 envia um email usando o modelo de email

Parabéns!🥳 Você completou este tutorial.

Aqui está uma breve demonstração do aplicativo:

Próximos Passos

Neste tutorial, você aprendeu como criar modelos de email com React Email e enviá-los usando Reenviar. Ambos os pacotes permitem que você integre facilmente a comunicação por email em suas aplicações.

Seja para notificações por email simples, boletins informativos ou campanhas de marketing, React Email e Resend oferecem uma solução eficiente e personalizável para atender às suas necessidades.

Como instalar o Resend em aplicações Next.js