現代軟體應用程式通常依賴電子郵件通訊來與使用者互動。例如,它們可能在登錄嘗試期間發送驗證代碼、行銷郵件或新聞通訊。這意味著電子郵件通知通常是與使用者溝通的最常見方式。

在本教程中,您將學習如何使用React Email設計出色的電子郵件模板,並使用Resend發送它們- 這是一個簡單而強大的電子郵件 API 平台。

先決條件

為了充分利用本教程,您應該具備React或Next.js的基本理解。

我們還將使用以下工具:

  • React Email:一個讓您使用React組件創建精美設計的電子郵件模板的庫。

  • Resend:一個從您的應用程式發送電子郵件的簡單而強大的 API 平台。

如何使用Next.js構建應用程式

在本部分中,您將創建一個簡單的客戶支援應用程式。該應用將包括一個供用戶提交查詢的表單,觸發發送電子郵件通知以確認已創建支援工單。

開始之前,我們將首先設置用戶界面和 API 端點。

運行以下命令來創建一個新的 Next.js TypeScript 項目:

npx create-next-app react-email-resend

更新 app/page.tsx 文件,以呈現一個表單,該表單收集客戶的詳細信息,包括他們的全名、電子郵件地址、工單主題以及描述問題的詳細消息。當表單被提交時,輸入數據將使用 handleSubmit 函數記錄到控制台中。

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

export default function Page() {
    //👇🏻 輸入狀態
    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();
        //👇🏻 記錄用戶輸入
        console.log({ name, email, subject, content });
    };
return ({/** -- UI 元素 -- */})
}

返回接受用戶全名、電子郵件地址、工單主題以及描述問題的詳細消息的表單 UI 元素。

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

這是從組件生成的頁面:

接下來,創建一個 API 端點 (/api/route.ts),用於接受客戶的輸入。

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

將以下代碼複製到 api/route.ts 文件中。API 端點在接收到客戶的輸入時將其記錄到控制台中。

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

export async function POST(req: NextRequest) {
    const { name, email, subject, content } = await req.json();
    //👇🏻 記錄內容
    console.log({ name, email, subject, content });
    return NextResponse.json({
        message: "Email sent successfully",
        data,
 });
}

更新 handleSubmit 函數,以將客戶的數據發送到 API 端點並返回 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("");
};

恭喜!您已經設置了數據收集和提交。在接下來的部分中,我將帶您逐步創建和發送使用 React Email 和 Resend 的電子郵件模板。

如何使用 React Email 創建電子郵件模板

React Email 讓你使用 React 和 TypeScript 建立並發送電子郵件元件。它支持多種電子郵件客戶端,包括 Gmail、Yahoo Mail、Outlook 和 Apple Mail。

React Email 還提供多個 UI 元件,使你能夠根據你偏好的佈局使用 React JSX/TSX 元件自訂電子郵件模板。

通過運行下面的代碼片段來安裝 React Email 套件及其元件:

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

在你的 package.json 文件中包含這段腳本。它指示 React Email 電子郵件模板在你的專案中的位置。

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

React Email 的一個功能是能夠在開發期間在瀏覽器中預覽你的電子郵件模板,讓你看到它在收件人電子郵件中的顯示效果。

接下來,在 Next.js 的 src 文件夾中創建一個 emails 文件夾,並在其中放置一個 TicketCreated.tsx 文件,然後將以下代碼片段複製到該文件中:

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

在上面的代碼片段中,我們導入了構建電子郵件模板所需的元件。

接下來,將 TicketCreated 元件添加到文件中,以使用 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>
    );
};

最後,導出它並為 props 添加默認值:

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

export default TicketCreated;

在終端中運行 npm run email 以預覽電子郵件模板。

這封電子郵件模板通知客戶他們的支援票已經建立,支援團隊的成員將會聯絡他們。

React Email 提供各種預設的電子郵件模板,讓您輕鬆製作不同用途的精美樣式郵件。您可以查看可用的演示來看看可能的範例。

如何使用 Resend 發送電子郵件

Resend 是一個簡單的電子郵件 API,讓您可以在軟體應用程式內發送郵件。它支援多種程式語言,包括 JavaScript(Next.js、Express、Node.js)、Python、PHP、Go 和 Rust 等。

由於 Resend 的共同創辦人 Bu Kinoshita 也是 React Email 的創作者,因此 Resend 和 React Email 可輕鬆整合在一起。

Resend 上建立帳戶。登入後,轉到儀表板上的 API 金鑰部分,將您的 API 金鑰複製到 .env.local 檔案中。

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

//👇🏻 .env.local 檔案

import { NextRequest, NextResponse } from "next/server";
更新 API 端點,以使用 React Email 模板發送電子郵件,如下所示:
import { v4 as generateID } from "uuid";
//👇🏻 票證 ID 生成函數
import TicketCreated from "@/emails/TicketCreated";
//👇🏻 匯入電子郵件範本
import { Resend } from "resend";
const resend = new Resend(process.env.RESEND_API_KEY);

export async function POST(req: NextRequest) {
    //👇🏻 匯入 Resend
    const { name, email, subject, content } = await req.json();
    //👇🏻 接收來自前端的客戶輸入
    console.log({ name, email, subject, content });
    //👇🏻 記錄它們
    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,
    });
}

//👇🏻 使用電子郵件範本發送電子郵件

恭喜!🥳 你已完成此教學。

這裡是應用程式的簡要演示:

下一步

在本教程中,您學會了如何使用 React Email 創建電子郵件範本並使用 Resend 發送它們。這兩個套件使您能夠輕鬆地在應用程式中集成電子郵件通信。

無論是簡單的電子郵件通知、新聞通訊還是行銷活動,React Email 和 Resend 都提供了一個高效且可自定義的解決方案,以滿足您的需求。

如何在 Next.js 應用程序中安裝 Resend