Introduction
Email communication is a vital aspect of modern web applications, and in this comprehensive guide, we'll show you how to wield its power effectively. Join us as we explore the intricate art of sending emails with React Emails, implementing resend functionality, and harnessing the capabilities of Next.js Server Actions. Whether you're a seasoned developer or just starting, this article will equip you with the knowledge and tools to streamline your email communication, making it an asset rather than a challenge in your web projects. Let's dive in and transform your email game!
First, let's kickstart our journey by initializing a next.js
project. We were using npm
for this task, but today I've chosen to leverage the blazing speed of Bun ๐ฅ to accelerate our project setup.
cd Desktop #navigating to desktop, I am using macos could be different in Windows so be aware.
bunx create-next-app@latest react-emails-resend-nextjs
After our project has been created. We should navigate to our created project, and open it with vscode
. In my case, I'll do that using terminal.
cd react-emails-resend-nextjs #since we are already in desktop directory. We just should navigate to our project directly
code . #open project with vscode.
Installing dependencies
We need to install some dependencies to achieve our goals with this project.
- React-Email: A collection of high-quality, unstyled components for creating beautiful emails using React and TypeScript.
- Resend: The best API to reach humans instead of spam folders. Build, test, and deliver transactional emails at scale.
- React-hook-form: Performant, flexible and extensible forms with easy-to-use validation.
- Zod: TypeScript-first schema validation with static type inference.
bun add resend react-email react-hook-form zod #installing our packages
Setup environments
After installing our packages. We now need to create an account in resend
and get our email service api key
. To do that we will open resend official website, and at top right of the page you can create your account. In my case I chose github to create my account easily.
Now you should create an api in home page of opened dashboard. This page will be opened after you login successfully.
After that copy your API Key.
Now go to your root directory of your project and create .env.local
file to save your API Key
in that file.
mkdir .env.local
And update your file like this
RESEND_API_KEY="your_resend_api_key_here"
Do not forget to update your global.css file to be like the code below
@tailwind base;
@tailwind components;
@tailwind utilities;
Create Components
Now, we need to create some components needed in our project. So in src/
directory let's create a new folder called components
, and create a file called input.tsx
import { FC, HTMLAttributes, HTMLInputTypeAttribute } from "react"
import {
FieldValues,
UseFormRegister,
RegisterOptions,
UseFormRegisterReturn
} from "react-hook-form";
type InputProps = {
label?: string
type?: HTMLInputTypeAttribute
register: UseFormRegisterReturn
error: string | null
} & HTMLAttributes<HTMLInputElement>
export const Input:FC<InputProps> = ({
label,
register,
error,
...rest
}) => {
return (
<div className="flex flex-col gap-1">
<input
className="p-2 rounded-lg border border-slate-400 outline-none hover:border-black placeholder:text-gray-600"
{...register}
{...rest}
/>
{error ? (
<span className="text-red-600 text-sm">
{error}
</span>
) : null}
</div>
)
}
type TextAreaProps = {
label?: string
type?: HTMLInputTypeAttribute
register: UseFormRegisterReturn
error: string | null
} & HTMLAttributes<HTMLTextAreaElement>
export const TextArea:FC<TextAreaProps> = ({
label,
register,
error,
...rest
}) => {
return (
<div className="flex flex-col gap-1">
<textarea
className="p-2 rounded-lg border border-slate-400 outline-none hover:border-black placeholder:text-gray-600"
rows={4}
{...register}
{...rest}
/>
{error ? (
<span className="text-red-600 text-sm">
{error}
</span>
) : null}
</div>
)
}
Setup Contact Form
Now, let's open our Home Page
and update it to be the form that we want;
"use client"
import { Input, TextArea } from "@/components/input";
import { useForm } from "react-hook-form";
import * as z from "zod"
import { zodResolver } from "@hookform/resolvers/zod"
import { useState } from "react";
import { sendEmailAction } from "./_actions";
const formSchema = z.object({
fullName: z.string().nonempty(), // required
email: z.string().email().nonempty(), // type of email and required
message: z.string().nonempty() // required
})
// Form values type
export type FormProps = z.infer<typeof formSchema>
export default function Home() {
const [data, setData] = useState<{
success: boolean
error?:string | null
loading: boolean
message?: string
}>({
success: false,
error: null,
loading: false,
message: ""
})
// create form hook
const {
register,
handleSubmit,
reset,
formState:{ errors }
} = useForm<FormProps>({
resolver: zodResolver(formSchema),
defaultValues: {
fullName: "",
email: "",
message: ""
}
})
// submit function
const submit = async (values: FormProps) => {
setData(prev => ({ ...prev, loading: true })) // set loading true for better ux experience
const data = await sendEmailAction(values); // call server action and send data to it.
if (data.success) { // if sent successfully
setData({
loading: false,
success: true,
error: null,
message: data.message
})
reset() // reset form fields
} else { // if there is an error
setData({
loading: false,
success: false,
error: data.error,
})
}
}
return (
<main className="my-20">
<div className="max-w-xl mx-auto border border-slate-500 shadow-xl p-5">
<h1 className="text-center font-bold text-2xl mb-5">Send Email</h1>
<form onSubmit={handleSubmit(submit)}>
<div className="grid grid-cols-1 gap-2">
{
!data.success && data.error ? (
<div className="my-1 p-2 bg-red-500/25 text-red-500 border border-red-500">
{data.error}
</div>
) : null
}
{
data.success && !data.error ? (
<div className="my-1 p-2 bg-green-500/25 text-green-500 border border-green-500">
{data.message}
</div>
) : null
}
<Input
placeholder="Full Name"
label="Full Name"
type="text"
register={register("fullName")}
error={errors?.fullName?.message || null}
/>
<Input
placeholder="Email"
label="Email"
type="text"
register={register("email")}
error={errors?.email?.message || null}
/>
<TextArea
placeholder="Message"
label="Message"
register={register("message")}
error={errors?.message?.message || null}
/>
<button type="submit" disabled={data.loading} className="bg-black text-white outline-none border-none p-2 rounded-lg disabled:opacity-50">
{data.loading ? "Sending ..." : "Send"}
</button>
</div>
</form>
</div>
</main>
)
}
Create Email Component
After design our form, now we will create Email Component
using react-email
. An email template to sen our mails.
First we need to install some dependencies to use in our email template
bun add @react-email/html @react-email/head @react-email/button @react-email/heading @react-email/link @react-email/row @react-email/column @react-email/text @react-email/tailwind
Now let's get our email template ready to use. Note: I will create this file at /src/components
with email.tsx
name.
import { FormProps } from '@/app/page'
import { Html } from '@react-email/html'
import { Button } from '@react-email/button'
import { Heading } from '@react-email/heading'
import { Head } from '@react-email/head'
import { Text } from '@react-email/text'
import { Row } from '@react-email/row'
import { Column } from '@react-email/column'
import { Tailwind } from '@react-email/tailwind' // to allow us use tailwind classes in email template
type Props = FormProps // receive contact data
const Email = ({ email, fullName, message }: Props) => {
return (
<Tailwind>
<Html lang='en'>
<Head>
<title>Test Resend Email with React Email & Next.js</title>
</Head>
<Heading as='h1' className='text-2xl mb-5 font-bold'>Hi! {fullName}</Heading>
<Row>
<Column>
<Text className='text-md my-2'>Message: {message}</Text>
</Column>
</Row>
<Row>
<Column>
<Text className='text-md my-2'>Your entered email was: {email}</Text>
</Column>
</Row>
<Row>
<Column>
<Button href='https://hamudeshahin.me' className='bg-black text-white rounded-lg px-4 py-2 text-lg'>Test Button</Button>
</Column>
</Row>
</Html>
</Tailwind>
)
}
export default Email
Our template is ready tp use now! ๐ฅณ
Create Server Action
Server Actions is a Next.js 13 feature that allows you to execute functions on the backend from the frontend. That mean you do not need to create an api to do some operations on database.
Now let's create our server action file in /src/app/_actions.ts
But before creating our server action file. We need to update our next.config.js
file.
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverActions: true,
},
}
module.exports = nextConfig
Now our server action file must be like this;
'use server' // tell next.js to use this at server-side not on the client-side.
import { Resend } from "resend";
import { FormProps } from "./page"; // import form data type
import Email from "@/components/email";
const RESEND_API_KEY = process.env.RESEND_API_KEY!
console.log('RESEND_API_KEY');
console.log(RESEND_API_KEY);
const resend = new Resend(RESEND_API_KEY)
// our server action function
export async function sendEmailAction(params:FormProps) {
try {
const res = await resend.sendEmail({
from: 'onboarding@resend.dev',
to: params.email,
react: Email(params),
subject: `Message from ${params.fullName}`
})
if (!res.id) {
return { success: false, error: "Something went wrong!" }
}
return { success: true, message: `Email has been sent to ${params.email}` }
} catch (err) { // catch any unknown error if happen
console.error(String(err));
return { success: false, error: String(err) }
}
}
Testing our Project
Now let's test our project and try to send an email!
Fill Data
Response After Success Sending
Received Email
Get Full Code
You can get full code of this project in my GitHub Repo ๐
Conclusion:
In this guide, we've mastered email communication in web applications. By combining React Email
,Resend
's resend functionality, and Next.js Server Actions
, we've turned email management into a breeze.
We initiated our project swiftly with Bun
, installed necessary dependencies, and crafted a sleek contact form. Our email template, powered by React Email, adds a professional touch.
Thanks to Next.js Server Actions, some backend operations became effortless. Whether you're a seasoned developer or just starting, this guide equips you to streamline email communication in your web projects.
Now, go ahead, elevate your email game, and create efficient, powerful applications. Unlock new opportunities in your web development journey. ๐ก๐งโจ #WebDevelopment #React #Nextjs #Emails