Send an email with Resend when a form is submitted

Send an email with Resend when a form is submitted

Trigger: eventTrigger

Sends an email using Resend when a form is submitted. The email is built using React and the data from the form.

Framework:

APIs used:

Repository:

/resend-email-form

Categories:

Marketing

Overview

In this project the user can submit a form which triggers a background job which sends an email using Resend. The email is built using React and the data from the form.

To get started with this project follow the instructions on the GitHub README page.

Key features:

  • Sending a React email using our Resend integration.
  • A form which triggers the background job when submitted.

Sending a React email using our Resend integration

The email is built using React, styled with CSS and sent using our Resend integration.

sendReactEmail.tsx

_87
client.defineJob({
_87
id: "resend-email-form",
_87
name: "Resend: send email on form submit",
_87
version: "1.0.0",
_87
trigger: eventTrigger({
_87
name: "send.email",
_87
schema: z.object({
_87
to: z.string(),
_87
subject: z.string(),
_87
text: z.string(),
_87
name: z.string(),
_87
from: z.string(),
_87
}),
_87
}),
_87
integrations: {
_87
resend,
_87
},
_87
run: async (payload, io, ctx) => {
_87
await io.resend.sendEmail("send-email", {
_87
to: payload.to,
_87
subject: payload.subject,
_87
text: payload.text,
_87
from: payload.from,
_87
// BasicEmail is the custom React component that will be used to style the email
_87
react: <BasicEmail name={payload.name} text={payload.text} />,
_87
});
_87
},
_87
});
_87
_87
// Email styling
_87
const main = {
_87
padding: "10px 0",
_87
backgroundColor: "#222094",
_87
};
_87
_87
const container = {
_87
margin: "0 auto",
_87
padding: "20px 0 48px",
_87
};
_87
_87
const section = {
_87
padding: "24px",
_87
border: "solid 2px #dedede",
_87
backgroundColor: "#fff",
_87
borderRadius: "5px",
_87
textAlign: "center" as const,
_87
};
_87
_87
const text = {
_87
textAlign: "left" as const,
_87
fontSize: "16px",
_87
};
_87
_87
const button = {
_87
fontSize: "14px",
_87
font: "bold",
_87
backgroundColor: "#28a745",
_87
color: "#fff",
_87
lineHeight: 1.5,
_87
borderRadius: "0.2em",
_87
textAlign: "center" as const,
_87
};
_87
_87
function BasicEmail({ name, text }: { name: string; text: string }) {
_87
return (
_87
<Html>
_87
<Head />
_87
<Preview>Welcome to Acme Inc!</Preview>
_87
<Body style={main}>
_87
<Container style={container}>
_87
<Section style={section}>
_87
<Text>Hey {name}!</Text>
_87
<Text>{text}</Text>
_87
<Button
_87
style={button}
_87
pY={4}
_87
pX={4}
_87
href="https://acmecompany.inc/"
_87
>
_87
Get started
_87
</Button>
_87
</Section>
_87
</Container>
_87
</Body>
_87
</Html>
_87
);
_87
}

A form which triggers the background job when submitted

When the form is submitted the email is populated with the form content, the background job is triggered, and the email is sent.

sendEmailForm.tsx

_105
"use client";
_105
_105
import { useRouter } from "next/navigation";
_105
import { useState } from "react";
_105
import { sendEmail } from "../_actions";
_105
_105
const SendEmailForm = () => {
_105
const [isSubmitted, setIsSubmitted] = useState(false);
_105
const [to, setTo] = useState("");
_105
const [from, setFrom] = useState("");
_105
_105
const router = useRouter();
_105
const handleRefresh = () => {
_105
setIsSubmitted(false);
_105
console.log(isSubmitted);
_105
router.refresh();
_105
};
_105
_105
async function action(data: FormData) {
_105
const to = data.get("to");
_105
if (typeof to !== "string" || !to) return;
_105
const subject = data.get("subject");
_105
if (typeof subject !== "string" || !subject) return;
_105
const name = data.get("name");
_105
if (typeof name !== "string" || !name) return;
_105
const text = data.get("text");
_105
if (typeof text !== "string" || !text) return;
_105
const from = data.get("from");
_105
if (typeof from !== "string" || !from) return;
_105
_105
//send the event to trigger the email.
_105
//You can use the returned event with the @trigger.dev/react package if you want more detailed Job progress in your UI
_105
const event = await sendEmail(to, subject, name, text, from);
_105
setIsSubmitted(true);
_105
}
_105
_105
return (
_105
<form
_105
action={action}
_105
className="flex flex-col gap-y-4 px-4 pb-4 sm:w-96 sm:px-0"
_105
>
_105
<input
_105
type="text"
_105
name="to"
_105
placeholder="Enter a 'to' email address"
_105
className="rounded p-1.5 text-slate-800"
_105
value={to}
_105
onChange={(e) => setTo(e.target.value)}
_105
/>
_105
<input
_105
type="text"
_105
name="subject"
_105
placeholder="Enter a subject"
_105
className="rounded p-1.5 text-slate-800"
_105
/>
_105
<input
_105
type="text"
_105
name="name"
_105
placeholder="Enter the name of the recipient"
_105
className="rounded p-1.5 text-slate-800"
_105
/>
_105
<textarea
_105
name="text"
_105
placeholder="Enter email text"
_105
className="rounded p-1.5 text-slate-800"
_105
/>
_105
<input
_105
type="text"
_105
name="from"
_105
placeholder="Enter a 'from' email address"
_105
className="rounded p-1.5 text-slate-800"
_105
onChange={(e) => setFrom(e.target.value)}
_105
/>
_105
<p className="text-sm text-gray-500">
_105
⚠️ The &quot;from&quot; email address must be a verified domain in your
_105
Resend account to work.
_105
</p>
_105
{!isSubmitted ? (
_105
<button
_105
type="submit"
_105
disabled={!isValidEmail(to) || !isValidEmail(from)}
_105
className="mt-2 h-10 w-full rounded bg-indigo-600 font-bold transition hover:bg-indigo-500 disabled:opacity-20"
_105
>
_105
✉️ Send email
_105
</button>
_105
) : (
_105
<div className="flex gap-2">
_105
<p>✅ Email sent! - </p>
_105
<button
_105
onClick={handleRefresh}
_105
className="text-slate-300 underline underline-offset-2 transition hover:text-slate-100"
_105
>
_105
Send another
_105
</button>
_105
</div>
_105
)}
_105
</form>
_105
);
_105
};
_105
_105
function isValidEmail(email: string) {
_105
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
_105
}
_105
_105
export default SendEmailForm;

How to run this project

Follow the instructions on the GitHub README page.