reCAPTCHA WAF Session Token

How to Send Emails with React Using Resend — SitePoint


In this article, we’ll look at how to send emails with React Email and Resend. We’ll also build a typical portfolio contact form for sending those emails using Next.js.

Until recently, creating and sending emails in React was extremely difficult, as there was no proper documentation on how to create email templates with hacky

tag tricks, or documentation on how to send emails.

Much of the difficulty with using emails has been alleviated by the creation of React Email and Resend. These products — which were developed by the same team — have created an amazing developer experience for working with emails.

List of Contents
  1. Setting Up the Next App
  2. Setting Up Resend
  3. Creating the Email Component
  4. Sending the Email with Resend
  5. Conclusion

Setting Up the Next App

Let’s start by setting up Next.js. Clone the starter branch of this GitHub repo to get the starter code. The image below shows what we should see when we run the development server.

The starter code consists of a simple Next.js 13 app (with the App Router) that has a contact form component with proper validation using Zod and React Hook Form.

We’ll be implementing the onSubmit function in the contact form component:

<code class="typescript language-typescript"><span class="token keyword">function</span> <span class="token function">onSubmit</span><span class="token punctuation">(</span>values<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token property-access">infer</span><span class="token operator"><</span><span class="token keyword">typeof</span> formSchema<span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  
  <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span>values<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code>

Note: we won’t cover how to build the form or how to style the email itself, as that can be done with Tailwind or regular CSS.

Setting Up Resend

Le’t now look at how to set up Resend.

Getting the API key

To send the email with the Resend SDK, we first need to retrieve an API key. Head over to Resend’s website and log in or create an account with your email or GitHub details.

After you’ve logged in, you should see the dashboard as pictured below.

The Resend dashboard, with Add API Key highlighted

Press the Add API Key button to get the API key. Once you have your API key, go to the root of the project and create a .env.local file and paste the API key as follows:

<code class="bash language-bash"><span class="token assign-left variable">RESEND_API_KEY</span><span class="token operator">=</span>************
</code>

This will allow us, later on, to use Resend services within our app.

Verifying a domain

Resend requires that we verify a domain from which we want to send unlimited emails by adding a DNS record on their website.

To do this, head over to the Resend dashboard and go to the Domains tab and press the Add Domain button, as pictured below.

The add domains button

From there, we can verify the domain and use that specific email address. For this simple tutorial, we won’t be verifying any email addresses.

Creating the Email Component

It’s now time to create the email component. In the components folder, create a file called Email.tsx and import the following components from React Email:

<code class="typescript language-typescript"><span class="token keyword">import</span> <span class="token imports"><span class="token punctuation">{</span>
  <span class="token maybe-class-name">Body</span><span class="token punctuation">,</span>
  <span class="token maybe-class-name">Container</span><span class="token punctuation">,</span>
  <span class="token maybe-class-name">Head</span><span class="token punctuation">,</span>
  <span class="token maybe-class-name">Heading</span><span class="token punctuation">,</span>
  <span class="token maybe-class-name">Hr</span><span class="token punctuation">,</span>
  <span class="token maybe-class-name">Html</span><span class="token punctuation">,</span>
  <span class="token maybe-class-name">Preview</span><span class="token punctuation">,</span>
  <span class="token maybe-class-name">Tailwind</span><span class="token punctuation">,</span>
  <span class="token maybe-class-name">Text</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></span> <span class="token keyword">from</span> <span class="token string">"@react-email/components"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token imports"><span class="token operator">*</span> <span class="token keyword">as</span> <span class="token maybe-class-name">React</span></span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
</code>

For the email, the only things that will change will be the form data values (that is, the name, message, email address, and phone number of the person). These values can be used as props for the email, so let’s create an interface for that:

<code class="typescript language-typescript"><span class="token keyword">interface</span> <span class="token class-name"><span class="token maybe-class-name">ContactMeEmailProps</span></span> <span class="token punctuation">{</span>
  name<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
  emailAddress<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
  phoneNumber<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
  content<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code>

The actual email component would look like this:

<code class="typescript language-typescript"><span class="token keyword">const</span> <span class="token function-variable function"><span class="token maybe-class-name">VercelInviteUserEmail</span></span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
  name<span class="token punctuation">,</span>
  content<span class="token punctuation">,</span>
  emailAddress<span class="token punctuation">,</span>
  phoneNumber<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token operator">:</span> <span class="token maybe-class-name">ContactMeEmailProps</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
</code>

For the preview text of the email, we could just say that “so and so has a message”. It would be implemented like this:

<code class="typescript language-typescript"><span class="token keyword">const</span> previewText <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> has a message</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
</code>

Now for the actual JSX. We’ll first need to wrap our email in an tag and render the and tags (for the preview text). Then we need to wrap the content in a tag to use Tailwind styling, and a tag:

<code class="typescript language-typescript"><span class="token operator"><</span><span class="token maybe-class-name">Html</span><span class="token operator">></span>
  <span class="token operator"><</span><span class="token maybe-class-name">Head</span> <span class="token operator">/</span><span class="token operator">></span>
  <span class="token operator"><</span><span class="token maybe-class-name">Preview</span><span class="token operator">></span><span class="token punctuation">{</span>previewText<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span><span class="token maybe-class-name">Preview</span><span class="token operator">></span>
  <span class="token operator"><</span><span class="token maybe-class-name">Tailwind</span><span class="token operator">></span>
    <span class="token operator"><</span><span class="token maybe-class-name">Body</span> className<span class="token operator">=</span><span class="token string">"bg-white my-auto mx-auto font-sans"</span><span class="token operator">></span>
      <span class="token punctuation">{</span><span class="token spread operator">...</span><span class="token punctuation">}</span>
    <span class="token operator"><</span><span class="token operator">/</span><span class="token maybe-class-name">Body</span><span class="token operator">></span>
  <span class="token operator"><</span><span class="token operator">/</span><span class="token maybe-class-name">Tailwind</span><span class="token operator">></span>
<span class="token operator"><</span><span class="token operator">/</span><span class="token maybe-class-name">Html</span><span class="token operator">></span>
</code>

We can then add a component with some general styling to make the container in which the email is rendered look nicer:

<code class="xml language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>Container</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>border border-solid border-[#eaeaea] rounded
my-[40px] mx-auto p-[20px] w-[465px]<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>Container</span><span class="token punctuation">></span></span>
</code>

Then inside the container, we can add a simple heading with some styles labeled “Someone would like to contact you about something!”

<code class="xml language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>Heading</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>strong</span><span class="token punctuation">></span></span>{name}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>strong</span><span class="token punctuation">></span></span> would like to contact you about something!
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>Heading</span><span class="token punctuation">></span></span>
</code>

Then we can render out the actual content of the email with the built-in component:

<code class="xml language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>Text</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-black text-[14px] leading-[24px]<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  Here is the message:
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>Text</span><span class="token punctuation">></span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>Text</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-black text-[14px] leading-[24px]<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  {content}
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>Text</span><span class="token punctuation">></span></span>
</code>

Finally, we can add an


component and another component with the sender’s contact information for future conversations:

<code class="xml language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>Hr</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>border border-solid border-[#eaeaea] my-[26px] mx-0 w-full<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>Text</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-[#666666] text-[12px] leading-[24px]<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  This message was sent by ${name}. You can contact him through his
  email {emailAddress} or his phone number {phoneNumber}
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>Text</span><span class="token punctuation">></span></span>
</code>

And with that, our email is done. As you’ve probably noticed, React Email makes it simple to make emails, because its built-in components are practically identical to regular HTML tags.

The email should look something like the image below.

Our basic email template

Now we’re ready to send the email with Resend!

Sending the Email with Resend

To send the email, we first need to implement the API endpoint. In the file api/send/route.ts (already created in starter files), make sure the following imports are present:

<code class="typescript language-typescript"><span class="token keyword">import</span> <span class="token imports"><span class="token maybe-class-name">ContactMeEmail</span></span> <span class="token keyword">from</span> <span class="token string">"@/components/Email"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token imports"><span class="token punctuation">{</span> <span class="token maybe-class-name">NextRequest</span><span class="token punctuation">,</span> <span class="token maybe-class-name">NextResponse</span> <span class="token punctuation">}</span></span> <span class="token keyword">from</span> <span class="token string">"next/server"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token imports"><span class="token punctuation">{</span> <span class="token maybe-class-name">Resend</span> <span class="token punctuation">}</span></span> <span class="token keyword">from</span> <span class="token string">"resend"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token imports"><span class="token operator">*</span> <span class="token keyword">as</span> z</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>
</code>

Then, create an instance of the Resend SDK, as follows:

<code class="typescript language-typescript"><span class="token keyword">const</span> resend <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name"><span class="token maybe-class-name">Resend</span></span><span class="token punctuation">(</span>process<span class="token punctuation">.</span><span class="token property-access">env</span><span class="token punctuation">.</span><span class="token constant">RESEND_API_KEY</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code>

Note: if you used a different environment variable name for your API key, make sure to replace it properly.

Then paste in the following Zod schema:

<code class="typescript language-typescript"><span class="token keyword">const</span> sendRouteSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token method function property-access">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  name<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token method function property-access">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">min</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  emailAddress<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token method function property-access">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  phoneNumber<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token method function property-access">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">min</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  content<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token method function property-access">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">min</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code>

This schema represents the request body that was sent from the client. Now let’s destructure the request body to get these fields in the POST function:

<code class="typescript language-typescript"><span class="token keyword">const</span> <span class="token punctuation">{</span> name<span class="token punctuation">,</span> emailAddress<span class="token punctuation">,</span> phoneNumber<span class="token punctuation">,</span> content <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> req
  <span class="token punctuation">.</span><span class="token method function property-access">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span>body<span class="token punctuation">)</span> <span class="token arrow operator">=></span> sendRouteSchema<span class="token punctuation">.</span><span class="token method function property-access">parse</span><span class="token punctuation">(</span>body<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code>

Now, to send the email, we use the send function from our Resend instance like this:

<code class="typescript language-typescript"><span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> resend<span class="token punctuation">.</span><span class="token property-access">emails</span><span class="token punctuation">.</span><span class="token method function property-access">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token keyword">from</span><span class="token operator">:</span> <span class="token string">"from email"</span><span class="token punctuation">,</span>
  to<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"delivery email"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  subject<span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> has a message!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
  react<span class="token operator">:</span> <span class="token function"><span class="token maybe-class-name">ContactMeEmail</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token punctuation">,</span> emailAddress<span class="token punctuation">,</span> phoneNumber<span class="token punctuation">,</span> content <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code>

If you verified your domain on Vercel, you can use an email address with that domain on the from field, and the to field should be your email. If you want to be extra secure with the email addresses, you can set them as environment variables.

Now we need to implement the actual fetch action on the client. In the contact form component (components/ContactForm.tsx), we need to fetch the API endpoint like this inside of the onSubmit function:

<code class="typescript language-typescript"><span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"/api/send"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  method<span class="token operator">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span>
  body<span class="token operator">:</span> <span class="token known-class-name class-name">JSON</span><span class="token punctuation">.</span><span class="token method function property-access">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    name<span class="token operator">:</span> values<span class="token punctuation">.</span><span class="token property-access">name</span><span class="token punctuation">,</span>
    emailAddress<span class="token operator">:</span> values<span class="token punctuation">.</span><span class="token property-access">email</span><span class="token punctuation">,</span>
    phoneNumber<span class="token operator">:</span> values<span class="token punctuation">.</span><span class="token property-access">phone</span><span class="token punctuation">,</span>
    content<span class="token operator">:</span> values<span class="token punctuation">.</span><span class="token property-access">content</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code>

Make sure to mark the function as async due to the await statement. It’s up to you to decide how you want to implement loading and error-handling states. (You can read more about async/await here.)

And with that, we have successfully sent the email with Resend!

Conclusion

Much of the headache with creating and sending emails in React has been solved with React Email and Resend. It’s a two-hit combo that provides an amazing developer experience and gets the job done extremely quickly.

Consult the docs for React Email and Resend if you want to learn more about these frameworks. React Email also provides many example templates for you to base your emails off.

You can find the finished source code on GitHub.





Source link

Leave a Reply

Your email address will not be published. Required fields are marked *