Las aplicaciones modernas de Software frecuentemente se basan en comunicación por email para interactuar con los usuarios. Podrían enviar códigos de autenticación durante intentos de inicio de sesión, emails de marketing, o boletines informativos, por ejemplo. Esto significa que las notificaciones de email son típicamente el medio más común de comunicación con los usuarios.

En este tutorial, aprenderás cómo diseñar plantillas asombrosas de email con React Email y enviarlos usando Resend – una potente plataforma API de correo electrónico.

Pre-requisitos

Para aprovechar lo máximo de este tutorial, deberías tener un entendimiento básico de React o Next.js.

También haremos uso de las siguientes herramientas:

  • React Email: Una librería que te permite crear plantillas de email diseñadas hermosamente usando componentes de React.
  • Resend: Una poderosa y sencilla plataforma API para enviar emails desde tus aplicaciones.

Cómo construir la Aplicación con Next.js

En esta sección, crearás una aplicación sencilla de soporte de cliente. La aplicación incluirá un formulario para usuarios para enviar sus solicitudes, el cual dispara una notificación de email confirmando que un ticket de soporte ha sido creado.

Para comenzar, primero configuraremos la interfaz de usuario y un endpoint de la API.

Ejecuta el siguiente comando para crear un nuevo proyecto de Next.js con TypeScript:

npx create-next-app react-email-resend

Actualiza el archivo app/page.tsx para renderizar un formulario que recoge los detalles del cliente, incluyendo su nombre completo, la dirección de email, el asunto del ticket, y un mensaje con detalles describiendo el problema. Cuando el formulario se envía, los datos son registrados a la consola usando la función 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 las entradas
    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();
        //👇🏻 registra las entradas del usuario
        console.log({ name, email, subject, content });
    };
return ({/** -- elementos de UI -- */})
}

Regresa los elementos UI del formulario que aceptan el nombre completo del usuario, la dirección de email, asunto del ticket, y un mensaje con los detalles describiendo el 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>
    );

Aquí está la página resultante del componente:

The Page component renders a form that accepts the user's input

Luego, crea un endpoint de la API (/api/route.ts) que acepta las entradas del cliente.

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

Copia el siguiente código en el archivo api/route.ts. El endpoint de la API registra la entrada del cliente a la consola después de recibirla.

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

export async function POST(req: NextRequest) {
    const { name, email, subject, content } = await req.json();
    //👇🏻 registra los contenidos
    console.log({ name, email, subject, content });
    return NextResponse.json({
        message: "Email enviado con éxito",
        data,
 });
}

Actualiza la función handleSubmit para enviar los datos del cliente al endpoint de la API y regresa la respuesta 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("Un error ocurrió, por favor intenta nuevamente más tarde");
    }
    setName("");
    setEmail("");
    setSubject("");
    setContent("");
};

¡Felicidades! Has configurado la colección de datos y el envío. En las próximas secciones, te mostraré cómo crear y enviar plantillas de email con React Email y Resend.

Cómo crear Plantillas de Email usando React Email

React Email te permite construir y enviar componentes de email usando React y TypeScript. Soporta múltiples clientes de email, incluyendo Gmail, Mail de Yahoo, Outlook, y Mail de Apple.

React Email también provee múltiples componentes UI que te permiten personalizar las plantillas de email según tu diseño preferido usando componentes de React JSX/TSX.

Instala el paquete React Email y sus componentes al ejecutar el fragmento de código de abajo:

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

Incluye este escript en tu archivo package.json. Dirige a React Email a dónde están localizados las plantillas de email en tu proyecto.

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

Una de las características de React Email es la habilidad de pre-visualizar tu plantilla de email en tu navegador durante el desarrollo, permitiéndote ver cómo aparecerá en el email del receptor.

Así que luego, crea una carpeta emails que contenga un archivo TicketCreated.tsx dentro de la carpeta src de Next.js y copia el siguiente fragmento de código en el archivo:

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";

En el fragmento de código de arriba, importamos los componentes necesarios para construir la plantilla de email.

Luego, agrega el componente TicketCreated al archivo para renderizar la plantilla de email usando los componentes de React Email.

export const TicketCreated = ({ username, ticketID }: TicketCreatedProps) => {
    return (
        <Html>
            <Head />
            <Preview>Email de Confirmación del Ticket de Soporte 🎉</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'>
                            Tu Ticket ha sido creado
                        </Heading>
                        <Text className='text-black text-[14px] leading-[24px]'>
                        Hola {username},
                        </Text>
                        <Text className='text-black text-[14px] leading-[24px]'>
                            <strong>El Ticket de Soporte</strong> (<Link href={`${baseUrl}/ticket/${ticketID}`} className='text-blue-600 no-underline'>{`#${ticketID}`}</Link>) ha sido creado con éxito.
                        </Text>

                        <Text className='text-black text-[14px] leading-[24px]'>El Equipo de Soporte revisará tu ticket y volverán contigo en breve.
                        </Text>

                        <Hr className='border border-solid border-[#eaeaea] my-[26px] mx-0 w-full' />
                        <Text className='text-[#666666] text-[12px] leading-[24px]'>Este mensaje estaba dirigido a {" "} <span className='text-black'>{username}</span>. Si no creaste este ticket, por favor ignora este email.
                        </Text>
                    </Container>
                </Body>
            </Tailwind>
        </Html>
    );
};

Finalmente, expórtalo y agrega un valor predeterminado para las props:

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

export default TicketCreated;

Ejecuta npm run email en tu terminal para pre-visualizar la plantilla de email.

6c5e1518-fc85-4d79-bd05-f4a2c2381976

Esta plantilla de email notifica a los clientes que su ticket de soporte ha sido creado y que alguien del equipo de soporte se comunicarán con ellos.

React Email ofrece una variedad de plantillas de email pre-diseñada, facilitando el crear email con estilos hermosos para distintos propósitos. Puedes revisar el demo disponible para ver ejemplos de lo que es posible.

Cómo enviar Emails con Resend

Resend es una API de email sencilla que te permite enviar emails dentro de tu aplicación de software. Soporta un montón de lenguajes de programación, incluyendo JavaScript (Next.js, Express, Node.js), Python, PHP, Go, and Rust, entre otros.

Resend y React Email pueden ser fácilmente integrados juntamente ya que el co-fundador de Resend, Bu Kinoshita, es también el creador de React Email.

Crea una cuenta en Resend. Una vez que iniciaste sesión, navega hacia la sección de claves de API en tu panel y copia tu clave de API en un archivo .env.local.

4a289abc-b7e5-4c81-b7ee-e8f084354fae
//👇🏻 archivo .env.local 
RESEND_API_KEY=<RESEND_API_KEY>

Actualiza el endpoint de la API para enviar un email usando la plantilla de React Email, como se muestra abajo:

import { NextRequest, NextResponse } from "next/server";
//👇🏻 función generado del ID del boleto
import { v4 as generateID } from "uuid";
//👇🏻 importa la plantilla de email
import TicketCreated from "@/emails/TicketCreated";
//👇🏻 imports Resend
import { Resend } from "resend";
const resend = new Resend(process.env.RESEND_API_KEY);

export async function POST(req: NextRequest) {
    //👇🏻 acepta la entrada del cliente desde el frontend
    const { name, email, subject, content } = await req.json();
    //👇🏻 los registra
    console.log({ name, email, subject, content });
    //👇🏻 envia una email usando la plantilla de email
    const { data, error } = await resend.emails.send({
        from: "Acme <onboarding@resend.dev>",
        to: [email],
        subject: "Email de Confirmación del Ticket 🎉",
        react: TicketCreated({ username: name, ticketID: generateID() }),
    });

    if (error) {
        return NextResponse.json(
            { message: "Hubo un error al enviar el email" },
            { status: 500 }
        );
    }

    return NextResponse.json({
        message: "El email se envió con éxito",
        data,
    });
}

¡Felicidades!🥳 Has completado este tutorial.

Aquí un breve demo de la aplicación:

Próximos Pasos

En este tutorial, aprendiste cómo crear plantillas de email con React Email y enviarlos usando Resend. Ambos paquetes te permiten integra la comunicación de email fácilmente con tus aplicaciones.

Ya sean simples las notificaciones de email, los boletines informativos, o campañas de marketing, React Email y Resend ofrecen una solución eficiente y personalizable para satisfacer tus necesidades.

Algunos recursos útiles incluyen:

¡Gracias por leer!